Java轻量级代码工程

一、背景简介

最近2年,很多公司接项目开始不挑剔了,只要核算下来有收益不会亏,就会库库的做各种没头没脑的项目,都是抱着多撑一天是一天的躺平心态。

如果项目和业务稳定,自然也有动力卷架构卷设计。

然而2024年对于很多研发团队的打工人来说,普遍都是处在随时卷铺盖走人的状态中,自然就是怎么省事怎么来,做项目时间和成本是最重视的维度。

抛开什么AI和各种工具加持,节省编程时间最有效的办法就是:拿现成的,最好只改个端口号。

二、工程结构

2024年上半年各种不大不小的项目写下来,其实从代码工程上看都是差不多的,服务端无非就是前和后两个代码工程,集成基础框架就可以增删改查了。

为了后续其它项目使用相同的基础工程,在第一个项目中,预留了代码工程的初期基础设计,方便那什么循环利用,在这篇文章简单分享一下。

基础的代码工程就这几块,实际上就是前后台两个单体服务,不涉及微服务和复杂架构,就是拿来应付各种奇怪的内部项目的快速开发;两个门面服务分别依赖framesharedthird三层代码包,然后运行启动类即可。

既然是单体服务,自然也不涉及数据库的拆分,能安稳运行就可以了。

xml 复制代码
<modules>
  <!-- 门面管理 -->
  <module>bm-facade</module>
  <!-- 后台管理 -->
  <module>bm-admin</module>
  <!-- 业务共享层 -->
  <module>bm-shared</module>
  <!-- 框架管理 -->
  <module>bm-frame</module>
  <!-- 第三方接入 -->
  <module>bm-third</module>
</modules>

三、模块化功能

3.1 框架模块

主要管理代码工程核心组件依赖,比如SpringBoot框架,MySQL数据库,MybatisPlus持久层,Swagger接口等,并且添加了一个公共过滤器。

java 复制代码
@Slf4j
@Component
public class CommonFilter extends OncePerRequestFilter implements Ordered {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain)
    throws ServletException, IOException {

        log.info("CommonFilter...doFilterInternal");

        // 请求向下转发
        chain.doFilter(request, response);
    }

    @Override
    public int getOrder() {
        return 999 ;
    }
}

对于一些必要的配置类和二次封装,也放在了这一层,另外为了简化工程的复杂性,使用AOP的方式包装了日志记录和令牌核验;

AOP切面编程就不说了,这个在项目中经常使用;Token令牌的封装方式可以自行扩展,权限校验拿数据的记录对比一下即可。

java 复制代码
@Component
public class BaseToken {

  @Getter
  @Setter
  private Long userId;

  @Getter
  @Setter
  private String userName;

  @Getter
  @Setter
  private String appName;

  @Getter
  @Setter
  private Long expireTime;

  private static final byte[] AES_KEY = Arrays.copyOf(MD5.create().digest(BaseToken.class.getPackage().getName()), 16);

  @Getter
  private final String currentType = BaseToken.class.getTypeName();

  public void expireTime(int effective) {
    expireTime = System.currentTimeMillis()/1000 + effective ;
  }

  public boolean expired() {
    return expireTime < (System.currentTimeMillis() / 1000);
  }

  public String toToken() {
    String data = JSONUtil.toJsonStr(this);
    return SecureUtil.aes(AES_KEY).encryptBase64(data);
  }

  public static BaseToken parseToken(String token) {
    String dataStr = SecureUtil.aes(AES_KEY).decryptStr(token);
    return JSONUtil.toBean(dataStr, BaseToken.class);
  }

  public boolean checkPermission (String... permissionCode) {
    AuthCheck authService = SpringUtil.getBean(AuthCheck.class);
    return authService.hasPermission(this.getUserId(), permissionCode);
  }

}

使用AOP切面编程拦截要鉴权的方法即可。

java 复制代码
@Component
@Aspect
@RequiredArgsConstructor
public class AuthAop {

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.butte.mound.frame.security.Auth)")
    public void logPointCut() {

    }

    @Around("logPointCut()")
    public Object around (ProceedingJoinPoint point) throws Throwable {
        try{
            // 检查权限
            checkAuth(point);
            // 执行方法
            Object result = point.proceed();
            return result;
        } catch (Exception e){
            e.printStackTrace();
            throw e ;
        }
    }

    private void checkAuth (ProceedingJoinPoint point){
        try{
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod();
            Auth auth = method.getAnnotation(Auth.class);
            BaseToken token = TokenContext.getToken();
            token.checkPermission(auth.authCode());
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

3.2 业务共享模块

主要管理业务代码,数据库相关的持久层文件,如果在服务层前后台业务差异过大的话,也可以考虑分2层管理即可,在体量小的项目中,持久层代码几乎差异不大,最多只是一些自定义查询。

3.3 前后台模块

前后台两个模块,主要就是API接入层,通常就是用户访问和系统管理的两个服务,在逻辑上并没有什么本质差异,为了方便不同角色的请求管理,在两个工程内各添加了一个拦截器。

java 复制代码
@Slf4j
@Component
public class FacadeInterceptor implements HandlerInterceptor {

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    log.info("req uri : {}",request.getRequestURI());

    String facadeToken = "令牌";

    BaseToken token = BaseToken.parseToken(facadeToken);
    TokenContext.setToken(token);

    return Boolean.TRUE ;
  }
}

3.4 第三方模块

至于常见的第三方API对接,比如短信服务,OSS文件存储,第三方登录等,如果考虑多个项目多次复用的话,可以单独拎一层出来,简单封装一层工具类,方便之后随时替换,当然也可以在业务工程中直接调用第三方的封装类。

四、源码地址

java 复制代码
文档仓库:
https://gitee.com/cicadasmile/butte-java-note

源码仓库:
https://gitee.com/cicadasmile/butte-mound
相关推荐
小鹭同学_8 分钟前
Java基础 Day20
java·开发语言
浩浩测试一下28 分钟前
Apache OFBiz 17.12.01 的远程命令执行漏洞 -Java 反序列化 + XML-RPC 请求机制
xml·java·安全·web安全·网络安全·apache·安全架构
27669582921 小时前
开盘啦 APP 抓包 逆向分析
java·python·app抓包·抓包分析·开盘啦
啥都想学的又啥都不会的研究生1 小时前
log日志最佳实践
java·spring boot·后端·spring·junit·log4j·logback
白开水不加冰1 小时前
JVM 的垃圾回收器
java·jvm
qq_12498707531 小时前
基于Spring boot+vue的中医养生系统的设计与实现(源码+论文+部署+安装+调试+售后)
java·vue.js·spring boot·后端·毕业设计
为美好的生活献上中指1 小时前
java每日精进 5.25【Redis缓存】
java·redis·缓存
吾日三省吾码1 小时前
Java 垃圾回收 (GC) 全面解析!
java·开发语言·jvm
比特森林探险记2 小时前
《Java vs Go:现代编程语言的核心差异与设计哲学对比》
java·开发语言·golang
海盐泡泡龟2 小时前
大文件上传如何做断点续传?(分别使用vue、React、java)
java·vue.js·react.js