java脚手架系列2--日志、国际化

之所以想写这一系列,是因为之前工作过程中有几次项目是从零开始搭建的,而且项目涉及的内容还不少。在这过程中,遇到了很多棘手的非业务问题,在不断实践过程中慢慢积累出一些基本的实践经验,认为这些与业务无关的基本的实践经验其实可以复刻到其它项目上,在行业内可能称为脚手架,因此决定将此java基础脚手架的搭建总结下来,分享给大家使用。

注意由于框架不同版本改造会有些使用的不同,因此本次系列中主要使用基本框架是 spring-boo-2.3.12.RELEASE和spring-cloud.-Hoxton.SR12,所有代码都在commonFramework项目上:https://github.com/forever1986/commonFramework/tree/master

1 日志

日志打印是项目脚手架基本功能,其目的包括统一日志管理,方便日志打印。市面上的日志框架有点多,那么我们如何去理解和选择呢?

1.1 门面日志和实现日志

首先,我们先理解门面日志实现日志日志门面日志实现的抽象层,日志实现是具体日志功能的实现。之所以有这2个东西,主要是为了避免日志框架改动,导致原先代码无法使用,因此使用门面日志定义日志统一的接口,然后其它日志实现根据统一接口进行实现,这样项目中通过使用门面日志与日志实现解耦效果。
常见的门面日志包括slf4j和JCL,JCL已经停止更新,因此现在基本上使用slf4j。
常见的日志实现包括logback、log4j、log4j2 等。

1.2 日志级别

不同的门面日志或者实现日志有着不同的日志级别。但是我们只需要了解以下几种即可:

  • TRACE:最低级别的日志记录,用于追踪程序的详细执行路径和调试信息。
  • DEBUG:用于记录调试信息,例如变量的值、方法的执行情况等。
  • INFO:用于记录程序的正常运行信息,例如应用程序启动、关键操作完成等。
  • WARN:用于记录警告信息,表示程序可能存在潜在的问题或异常情况。
  • ERROR:最高级别的日志记录,用于记录错误信息和异常情况。

1.3 实践

如果项目中只是引入门面日志,是不会打印日志的,因此需要配合一个日志实现。现在还有一个更为简便封装的框架lombok,其本身为了让实体类通过注解的方式提供有参构造、无参构造、get、set、tostring等方法,比如在类前面使用@Data则表示该类中的所有变量有get和set方法。而lombok另外一个功能就是提供实现slf4j的注解,通过@Slf4j注解到某个类,则等同于注入logger类到该类下面:

private final static Logger log= LoggerFactory.getLogger(XXXX.class);

在代码中可以使用log.xxx即可打印日志。在实践中,我们一般通过AOP切面功能自动打印日志,也通过实现注解方式注入类和方法的一些标识。下面通过引入spring-boot-starter-web依赖(默认有logback依赖)和lombok模块(引入slf4j依赖)来实现该功能

请参照common-log和manage-biz子模块

1)在commonFramework项目下面建立common子模块,在common子模块下面建立common-log(该子模块以spring.factories方式引入项目)。common-log子模块的功能是引入lombok依赖,同时实现AOP切面日志自动打印以及实现注解方式对一些类和方法进行标识
2)common-log子模块的pom文件引入如下依赖:

<!-- AOP切面 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 日志门面 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<!-- 获取Http Servlet相关配置 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3)设置spring.factories和configure类
在resources下面的META-INF下面建立spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.demo.common.log.config.LogConfiguration

配置LogConfiguration 日志配置

package com.demo.common.log.config;

import com.demo.common.log.aspect.LogAspect;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class LogConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public LogAspect logAspect() {
        return new LogAspect();
    }
}

4)设置AOP的切点LogAspect.java

package com.demo.common.log.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Aspect
@Slf4j
public class LogAspect {

    @Pointcut("execution(public * com.demo..*.controller..*.*(..)) || @annotation(com.demo.common.log.aspect.SysLog)") //controller包下的所有方法都打日剧
    public void logPointCut(){
    }

    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint){
        log.info("方法执行前...");
        SysLog sysLog = getAnnotationLog(joinPoint);
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if(sra != null){
            HttpServletRequest request = sra.getRequest();
            log.info("ip:" + request.getRemoteHost());
            log.info("url:" + request.getRequestURI());
            log.info("method:"+request.getMethod());
            log.info("class.method:" + joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
            log.info("args:" + joinPoint.getArgs());
            log.info(" 模块编码:"+sysLog.module().getCode());
            log.info(" 模块名称:"+sysLog.module().getName());
            log.info(" 方法描述:"+sysLog.description());
        }
        log.info("----------AOP日志end---------------");
    }

    private SysLog getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        return method != null ? method.getAnnotation(SysLog.class) : null;
    }
}

5)先建注解,为了通过注解方式设置一些类和方法的标识

package com.demo.common.log.aspect;


import java.lang.annotation.*;
import com.demo.common.log.enums.ModuleTypeEnum;

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {

    /**
     * 操作模块
     */
    ModuleTypeEnum module();


    /**
     * 操作描述
     */
    String description() default "";
}

6)在子模块manage-biz中引用common-log子模块,这样就可以默认controller层会自动打印日志,如果要让controller增加更为精确表示,可以使用@SysLog注解增加模块和操作描述

2 国际化

在项目后端,经常需要返回一些异常信息或者提示等等,而如果项目是针对不同地区(比如中国、美国等),那么需要做到不同环境(在中国或者美国)后端也可以实现中英文切换,也就是在应用程序中实现多语言支持和区域设置的功能,因此需要引入国际化功能。

2.1 基本概念

  • 语言标签(Language Tag) 语言标签是用来标识某个语言或语言和国家/地区的组合的字符串。语言标签通常由语言代码(ISO 639-1或ISO 639-3)和国家/地区代码(ISO 3166-1 Alpha-2)组成,使用"-"号分隔。例如,"en-US"表示英语(English)和美国(United States)的组合。
  • 资源束(Resource Bundle) 资源束是包含本地化文本和对象的集合。每个资源束都包含了一个或多个语言的本地化资源,可以根据语言标签来选择不同的资源束。资源束通常以.properties文件的形式存在,包含了一系列键值对(key-value)的配置项。
  • 区域设置(Locale) 区域设置是指某个特定的国家或地区的语言和文化习惯的组合。在Java中,区域设置由Locale类表示,可以通过构造函数或静态方法来创建。例如,Locale.US表示美国的区域设置,Locale.CHINA表示中国的区域设置。

简单来说,就是通过Locale获取到语言标签,再通过语言标签去不同资源束中获得对应的文字(中文、英文等)

2.2 代码实现

请参考manage-biz子模块

1)在resources目录下新建i18n文件夹
2)在i18n目录下,先建messages.properties、messages_en_US.properties、messages_zh_CN.properties三个文件
3)3个文件分别写入key-value,其中key为一致,value则使用中英文不同描述
4)在yaml文件中配置国际化路径

spring:
  # 配置国际化
  messages:
    basename: i18n/messages

5)新建获取国际化的公共类

package com.demo.manage.biz.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;

@Component
public class MessagesUtil {
    @Autowired
    MessageSource messageSource;


    public String getMessage(String key){
        return messageSource.getMessage(key, null, LocaleContextHolder.getLocale());
    }
}

6)这样就可以在项目中通过key方式获取国际化功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值