Springboot项目结构拆分(职责角度)

  • Post author:
  • Post category:其他



最基础的

:controller,service,util,model


常见的

:exception,handler,constant,listener,

config



陌生的

:holder,DataSource.marker,cache,comparator.attribute,



config解释:

@Configuration定义配置类,跟xml文件里的<Beans>做映射,@bean=<Bean>,存在bean不生效的情况'使用了默认的装配'使用@Primary解决
@mapperscan注解:一般做do和tem绑定,在整个类里,需要注意的就是datasource。




DataSource.marker


实际上就是一些接口,用于做标记,作用跟自定义注解类似,但使用更为方便,不过需要在使用到的地方支持对接口做校验

比如

多数据源配置

:MasterDataSourceMarker,依托于mapperscan的值’markerInterface’,然后连接信息上使用@ConfigurationProperties,映射到对应的xml文件,这样就实现了主从数据源的连接配置。

@MapperScan(markerInterface = MasterDataSourceMarker.class,basePackages = 
{"com.alphaliongroup.account.common.model"},sqlSessionTemplateRef = "masterSqlSessionTemplate")
和
public interface AccountTypeDetailAttributeDOMapper extends MasterDataSourceMarker {




cache


代码书写的原则就是尽可能复用,像cache,在多个地方都会用到,抽出来集中在一起,思路更加清晰。在很多项目里,代码都是在一直做重复,缺点显而易见:代码冗余繁杂,影响后续的业务。

cahe在项目中的结构



holder:

这个命名让我有点奇怪,但它的本质不复杂,就是在干@autowired的活,像这种方式,实际上就是因为在项目没有启动时(一般是测试),spring不能为bean注入,所以选择手动的方式来做注入。当然@SpringBootTest实际上也是有一样的功能(

这里暂时存疑,因为没有实践过

)。

public class ApplicationContextHolder {
    private static volatile ApplicationContext context = null;

    public static final ApplicationContext getContext(){
        return context;
    }

    public static final <T> T getBean(Class<T> clazz){
        return context.getBean(clazz);
    }

    public static void setApplicationContext(ApplicationContext applicationContext) {
        context = applicationContext;
    }
}



exception和handler

exception没什么可说的,就是自定义异常,一般也只会有message作为异常处理的方法参数。handler则是对应的统一异常返回,需要注意的是返回给前端页面的一般是json格式的数据,需要特别注意。

/**
 * @author vic 定义全局异常处理
 * @RestControllerAdvice 是@controlleradvice 与@ResponseBody 的组合注解
 */
@RestControllerAdvice
@Slf4j
public class GlobalControllerExceptionHandler {

    public static final String NOT_NULL_NOTICE = "should not be null";

    @ExceptionHandler(value = {BindException.class})
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    public Result bindException(BindException ex) {
        log.error("", ex);
        return Result.fail(ex.getFieldError().getField() + ": " + ex.getFieldError().getRejectedValue()+","+ex.getFieldError().getDefaultMessage());
    }



comparator.attribute:

这个让我比较困惑:它的功能是做两个字符串或日期的比较,但嵌套的层级比较多。

1.AttributeConditionOperationEnum:这个枚举类决定了比较的方向(小于大于相似)
2.AttributeTypeEnum:将多种类别的比较做成枚举类,DATE("date",new DateAttributeConditionMatcher())
3.AttributeConditionMatcher:接口
4.DateAttributeConditionMatcher,TextAttributeConditionMatcher:实现

使用:
AttributeTypeEnum attributeTypeEnum = AttributeTypeEnum.TEXT;
                        if(attributeMap.get(entry.getKey()) != null) {
                            flag = flag && attributeTypeEnum.getMatcher().match(entry.getValue(), 
                            String.valueOf(attributeMap.get(entry.getKey())), enumMapMap.getKey());



listener:

简单介绍一下通过自定义注解来控制监听的接口

自定义注解监听可以对请求做监听,kafka topic的监听可以使用直接监听

通过自定义注解@permission,以及value(这里还写了一个常量类来控制)

ApplicationListener<ContextRefreshedEvent> :核心接口,实现该接口,补全onApplicationEvent方法,
我们自定义的监听处理器生效,同时所有的监听上的逻辑处理也在这里完成。

@Permission(Permissions.Account)
public class AccountController {
每个接口都绑定了对应的permission,获取到注解,再做对应解析,就能做监听
步骤
WorkflowEventDispatcher.addListener(type, workflowListener);
将所写的监听加入,怎么确定监听范围(接口数量?)



版权声明:本文为weixin_43343786原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。