课外运动系统结构学习

问题:系统参数是什么
每学期给学生生成跑步任务,跑步成绩计算。
小程序上报的问题,跑一千米只有700米类似。

dev 测试
local 生产

1. 背景

杨老师希望我接受这个项目,并且能全部理解并加以开发和修改
我自己也可以通过学习这个项目来增长自己的能力。

2. 项目介绍

项目是标准的企业级spring cloud项目,包含多个服务,代码量大。

3. 服务学习

3.1. auth:认证服务

3.1.1. aspect包

其中进行切片编程,简而言之:当你调用distributeResources2Role的时候会自动异步调用refreshRoleResourceCache方法。

@Aspect  
@Component  
public class RoleResourceCacheAop {  
    @Autowired  
    private RoleService roleService;  
   // 定义切入点,即监听distributeResources2Role方法
    @Pointcut("execution(public * com.onesports.service.auth.web.RoleController.distributeResources2Role(..))") 
    public void roleResourceUpdate() {  
    }  
  // 在调用distributeResources2Role的时候,将返回值作为ret,开启线程异步调用refreshRoleResourceCache方法
    @AfterReturning(returning = "ret", pointcut = "roleResourceUpdate()")  
    public void doAfter(Object ret) {  
        Thread thread = new Thread(() -> roleService.refreshRoleResourceCache());  
        thread.start();  
    }  
}

3.1.2. client包

其中包含一个接口文件,作为定时任务在quartzJob包中实现。

3.1.3. config包

配置了 redis 和 swagger
redis 配置了RedisCacheManager 比 redisTemplate 更高一层的抽象

3.1.4. database包

存储了一个数据库文件,具体是什么没有仔细看

3.1.5. model包

包含在服务中需要用到的request对象 response对象等

3.1.6. quartzJob包

其中基于quartz框架进行了对定时任务增删改查的封装
重写了executeInternal 方法,后续可以使用这个组件来调用这个定时方法

@Component("overNightJob")  
@Slf4j  
public class OverNightJob extends QuartzJobBean {  
    @Autowired  
    BusinessClient businessClient;  
    @Override  
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {  
        log.info("定时任务触发");  
        businessClient.doOverNightJob();  
    }  
}

3.1.7. repository包

其中定义了多个JPA用到的对数据库增删改查的类

3.1.8. resource包

其中定义了保存系统日志的api和获取系统参数的api

3.1.9. service包

  • AuthStartupRunner:在服务启动后更新role 的缓存。
    • 实现了CommandLineRunner接口,重写run方法。服务启动后会调用run
    • ApplicationRunner 和 CommandLineRunner都有run方法,都会在应用启动后直接调用,CommandLineRunner接收简单的命令行参数,ApplicationRunner接收的参数更为复杂。
  • OverNightBacthRunner
    • 在应用运行之后实现调用定时任务OverNight任务
  • 其他文件,定义了服务需要的接口:比如user,resource,param等

3.1.10. validator包

  • 实现了一个ModifyUserRequestValidator类
    • 实现了Validator接口,其中support方法判断类型是否兼容,validate方法实现鉴权的部分
@Component("modifyUserRequestValidator")  
public class ModifyUserRequestValidator implements Validator {    
    @Autowired  
    UserRepository userRepository;  
    @Autowired  
    private MessageSource messageSource;  
    // 这个validator 兼容ModifyUserRequest和其父类
    @Override  
    public boolean supports(Class<?> aClass) {  
        return ModifyUserRequest.class.isAssignableFrom(aClass);  
    }  
    @Override  
    public void validate(@Nullable Object target, Errors errors) {  
        if (errors.hasErrors()) {  
            return;  
        }  
        if (Objects.isNull(target)) {  
            return;  
        }  
        ModifyUserRequest request = (ModifyUserRequest) target;  
        if (!userRepository.existsById(request.getId())) {  
            errors.reject("id", messageSource.getMessage("用户不存在", null, Locale.CHINA));  
        }  
    }  
}

validator会在之后被显式调用

3.1.11. web包

提供了多个服务的接口

  • 批处理信息
  • 校园信息
  • 机构信息
  • 日志信息
  • 登录操作管理
  • 参数管理
  • 系统资源管理
  • 角色分配资源管理
  • 用户信息管理

3.2. base-data服务

3.2.1. client包

提供两个接口

  • sessionsIsExistByPlaceId:根据场地id查询判断场次是否存在
  • deleteUploadFileByIds:根据文件id链删除文件

3.2.2. config包

swagger
ModelMapper配置:ModelMapper是简化配置对象映射的类,这里配置了对象之间的匹配策略是LOOSE(宽松)
以下是几种常用的匹配策略:

  • MatchingStrategies.STRICT:严格匹配策略,要求源对象和目标对象的字段名完全一致,包括大小写。
  • MatchingStrategies.LOOSE:宽松匹配策略,允许源对象和目标对象的字段名有一定的差异,例如大小写不一致或者使用了下划线命名。
  • MatchingStrategies.STANDARD:默认的标准匹配策略,与严格匹配策略相同,要求字段名完全一致。

3.2.3. model包

3.2.4. repository包

3.2.5. service包

提供了多个接口

  • 闸机信息管理
  • 人脸信息管理
  • 商户信息管理
  • 营业点信息管理
  • 场区信息管理
  • 场馆信息管理
  • 运动类型信息管理
  • 系统参数

3.2.6. web包

与service包基本一致

3.3. business服务:主要的业务

3.4. common服务 字典类

3.4.1. config包

swagger

3.4.2. model包

3.4.3. resource包

实现一个WebMessageResource类
这个类 实现对消息的管理还包含了对字典数据的查询

3.4.4. service包

提供了多个接口

  • 序列号自增
  • 字典删除
  • 提醒信息操作
  • 文件上传操作

3.4.5. web包

提供service中的api

3.5. common-core

3.5.1. annotation包:创建注解ExcelAnno

这个注解标记用来在导出excel操作的类的字段

import java.lang.annotation.*;  
// 这个注解用在字段上,是运行时也需要的注解,可被继承
@Target(ElementType.FIELD)  
@Retention(RetentionPolicy.RUNTIME)  
@Inherited  
public @interface ExcelAnno {  
  
    /**  
     * 在excel文件中某列数据的名称  
     *  
     * @return 名称  
     */  
    String cellName() default "";  
  
    /**  
     * 在excel对应的列  
     *  
     * @return  
     */  
    String excelCol() default "";  
  
    /**  
     * 实体中的字段类型  
     *  
     * @return  
     */  
    FieldDataType fieldDataType() default FieldDataType.STRING;  
  
    /**  
     * 案件导入时对应的数据类型  
     *  
     * @return  
     */  
    FieldType fieldType() default FieldType.CASE;  
  
    /**  
     * 是否必输  
     *  
     * @return  
     */  
    FieldInput fieldInput() default FieldInput.NO;  
  
    /**  
     * 实体中的字段类型枚举  
     */  
    enum FieldDataType {  
        STRING,  
        INTEGER,  
        DOUBLE,  
        DATE,  
        DATETIME,  
        BIGDICIMAL,  
        PERCENT,  
        ENUM,  
        LONG  
    }  
  
    /**  
     * 字段是否必输  
     */  
    enum FieldInput {  
        YES,  
        NO  
    }  
  
    /**  
     * 字段属性类型  
     */  
    enum FieldType {  
        CASE,  
        CONTRACT,  
        PERSONAL,  
        PERSONAL_HOUSE,  
        PERSONAL_INCOME,  
        PERSONAL_CONTACT,  
        PRODUCT,  
        PRODUCT_SERIES,  
        PERSONAL_JOB  
    }  
}

3.5.2. config包

  • baseconfig
    • setHeaderToken:设置了接收参数token,请求头参数,是非必须的
@Configuration  
public class BaseConfig {  
  
    public List<Parameter> setHeaderToken() {  
        ParameterBuilder tokenPar = new ParameterBuilder();  
        List<Parameter> pars = new ArrayList<>();  
        tokenPar.name("X-UserToken").description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();  
        pars.add(tokenPar.build());  
        return pars;  
    }  
}
  • redisconfig
  • webconfig
    • 添加了一个参数处理器LoginUserMethodArgumentResolver,用来判断前端传递的参数是否包含token
    • configureMessageConverters方法:将参数中的Long类型转化成字符串。
    • addResourceHandler:将静态资源的path定向到某个目录
@EnableWebMvc  
@Configuration  
public class WebConfig implements WebMvcConfigurer {    
    private static final Logger logger = LoggerFactory.getLogger(WebConfig.class);  
    @Autowired  
    private RequestMappingHandlerAdapter handlerAdapter;
    // 添加一个参数解析控制器,判断请求头是否包含token  
    @Override  
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {  
        argumentResolvers.add(currentUserMethodArgumentResolver());  
    }  
    @Bean  
    public LoginUserMethodArgumentResolver currentUserMethodArgumentResolver() {  
        return new LoginUserMethodArgumentResolver();  
    }  
    // 将参数中的Long类型转化成String
    @Override  
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {  
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();  
        ObjectMapper objectMapper = new ObjectMapper();  
        SimpleModule simpleModule = new SimpleModule();  
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);  
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);  
        objectMapper.registerModule(simpleModule);  
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);  
        converters.add(jackson2HttpMessageConverter);  
    }  
  // 将静态资源重定向到目录下
    @Override  
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        registry.addResourceHandler("swagger-ui.html")  
                .addResourceLocations("classpath:/META-INF/resources/");  
        registry.addResourceHandler("/webjars/**")  
                .addResourceLocations("classpath:/META-INF/resources/webjars/");  
    }  
}
// 这个是参数解析判断token的代码
public class LoginUserMethodArgumentResolver implements HandlerMethodArgumentResolver {  
    @Autowired  
    private RedisTemplate<String, UserModel> operatorTokenRedisTemplate;  
  
    @Override  
    public boolean supportsParameter(MethodParameter parameter) {  
        return parameter.getParameterType().isAssignableFrom(UserModel.class);  
    }  
  
    @Override  
    public Object resolveArgument(  
            MethodParameter parameter,  
            ModelAndViewContainer mavContainer,  
            NativeWebRequest webRequest,  
            WebDataBinderFactory binderFactory) throws Exception {  
        String accessToken = webRequest.getHeader("X-UserToken");  
        UserModel userModel = null;  
  
        if (isBlank(accessToken) ||  
                null == (userModel = operatorTokenRedisTemplate.opsForValue().get("TOKEN:" + accessToken))) {  
            throw new BadRequestException(null, this.getClass().getSimpleName(), "{403}当前请求需要用户登录");  
        }  
        return userModel;  
    }  
}

3.5.3. enum包

包含多个枚举类,所有的常量都在这里

3.5.4. expetion包

包含一个自定义的BadRequestException类,继承RuntimeException

3.5.5. jpa包

实现一个雪花id生成api,继承IdentifierGenerator

3.5.6. model包

3.5.7. utils包

各种工具类

3.5.8. web包

包含

  • exception处理
  • 使用Mysql查询请求的基类
  • 使用BigDecimal序列化钱的数字
  • 切片记录日志,所有接口调用的时间等

3.6. data-sync服务:将本地和远程的数据库表进行同步

3.6.1. config包

  • MybatisPlusConfig:动态表,分页,乐观锁等插件配置
  • MyTableNameHandler:动态表名,将表名和后缀存储在两个线程中,然后对表名进行重新构建

3.6.2. domain包

表信息,存放表名及建表sql

3.6.3. mapper包

存放了LocalMapper和RemoteMapper:

  • Mapper层,负责数据库查询
  • 使用DS注解,切换数据源为local或者remote

3.6.4. service包

实现了本地和远程数据库的对表的操作的接口

3.6.5. task包

实现将本地和远程数据库同步,将本地表推送给远程

3.7. entity:实体类服务

在这个服务中定义所有的实体类,分不同服务进行定义

3.8. Eureka:注册中心

3.9. exercise:运动服务

3.9.1. client包

3.10. gateway:网关服务

提供了拦截器,拦截请求,判断token

3.11. message:消息服务

3.11.1. config包

  • ApplicationContextConfig:通过name获取bean,通过class获取bean,通过name calzz获取bean
  • MessageSocketServer:向在线的用户推送消息

3.12. system-docking:闸机服务

3.12.1. config包

  • tomcat配置:更改tomcat的协议
  • CAS(单点登录)配置:
@Configuration  
public class CasFilterConfig {  
    /**  
     * 需要走cas拦截的地址(/* 所有地址都拦截)  
     */  
    private final static String URL_PATTERN = "/api/docking/getLoginUserInfo";  
  
    /**  
     * 默认的cas地址,防止通过 配置信息获取不到  
     */  
    @Value("${cas.server-url-prefix}")  
    private String casServerUrlPrefix;  
  
    /**  
     * 默认的cas地址,防止通过 配置信息获取不到  
     */  
    @Value("${cas.server-login-url}")  
    private String casServerLoginUrl;  
  
    /**  
     * 应用访问地址(这个地址需要在cas服务端进行配置)  
     */  
    @Value("${cas.client-host-url}")  
    private String casClientHostUrl;  
  
    @SuppressWarnings({ "rawtypes", "unchecked" })  
    @Bean  
    public ServletListenerRegistrationBean servletListenerRegistrationBean() {  
        ServletListenerRegistrationBean listenerRegistrationBean = new ServletListenerRegistrationBean();  
        listenerRegistrationBean.setListener(new SingleSignOutHttpSessionListener());  
        listenerRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);  
        return listenerRegistrationBean;  
    }  
  
    /**  
     * 单点登录退出  
     *  
     * @return  
     */  
    @SuppressWarnings({ "rawtypes", "unchecked" })  
    @Bean  
    public FilterRegistrationBean singleSignOutFilter() {  
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();  
        registrationBean.setFilter(new SingleSignOutFilter());  
        registrationBean.addUrlPatterns(URL_PATTERN);  
        registrationBean.addInitParameter("casServerUrlPrefix", casServerUrlPrefix);  
        registrationBean.setName("CAS Single Sign Out Filter");  
        registrationBean.setOrder(2);  
        return registrationBean;  
    }  
  
    /**  
     * 单点登录认证  
     *  
     * @return  
     */  
    @SuppressWarnings({ "rawtypes", "unchecked" })  
    @Bean  
    public FilterRegistrationBean AuthenticationFilter() {  
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();  
        registrationBean.setFilter(new AuthenticationFilter());  
        registrationBean.addUrlPatterns(URL_PATTERN);  
        registrationBean.setName("CAS Filter");  
        registrationBean.addInitParameter("casServerLoginUrl", casServerLoginUrl);  
        registrationBean.addInitParameter("serverName", casClientHostUrl);  
        registrationBean.setOrder(3);  
        return registrationBean;  
    }  
  
    /**  
     * 单点登录校验  
     *  
     * @return  
     */  
    @SuppressWarnings({ "rawtypes", "unchecked" })  
    @Bean  
    public FilterRegistrationBean Cas30ProxyReceivingTicketValidationFilter() {  
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();  
        registrationBean.setFilter(new Cas30ProxyReceivingTicketValidationFilter());  
        registrationBean.addUrlPatterns(URL_PATTERN);  
        registrationBean.setName("CAS Validation Filter");  
        registrationBean.addInitParameter("casServerUrlPrefix", casServerUrlPrefix);  
        registrationBean.addInitParameter("serverName", casClientHostUrl);  
        registrationBean.setOrder(4);  
        return registrationBean;  
    }  
  
    /**  
     * 单点登录请求包装  
     *  
     * @return  
     */  
    @SuppressWarnings({ "rawtypes", "unchecked" })  
    @Bean  
    public FilterRegistrationBean httpServletRequestWrapperFilter() {  
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();  
        registrationBean.setFilter(new HttpServletRequestWrapperFilter());  
        registrationBean.addUrlPatterns(URL_PATTERN);  
        registrationBean.setName("CAS HttpServletRequest Wrapper Filter");  
        registrationBean.setOrder(5);  
        return registrationBean;  
    }  
}
  • fastjson配置:确定了string和json的转化规则
  • swagger

3.12.2. schedule包

定时任务:同步人脸信息

3.13. membercard服务

3.13.1. config包

  • druid配置:druid是一个高性能的数据库处理池。

3.14. wechat服务

4. 业务api调用(从前端查看)

4.1. 管理端(主要是exercise服务,包含个别business和auth服务)

  • 课外运动跟踪:
    • queryRequireInfoByStatus
    • queryFacultyClassTree
  • 课外运动计划:
    • queryPlanInfoByPage
  • 课外运动成绩
    • queryParentClassList
    • queryAllAcademicYear
    • queryFacultyClassList
    • queryTaskInfo
  • 运营中心
    • queryPlanInfoByTeacherId
    • getAnnouncementTypeNum
    • getAnnouncementByPage
    • querySafetyTipsPhoto
  • 基础数据管理
    • queryMotionClass
    • queryPlanInfoByTeacherId
    • queryAcademicYear
    • querySunTeacherInfo
    • queryConfigurationSportsTeacherInfo
    • queryRunningArea

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 2738430398@qq.com