Springboot 返回数据提示语 国际化 (AOP实现)

简介: Springboot 返回数据提示语 国际化 (AOP实现)

前言



本篇内容:


提示语的国际化返回,自定义多语言。


本文使用aop方式,拦截接口返回的数据,进行转换。


正文



先看这次示例教学的项目 目录结构:


image.png


(当然resource里面的i18n文件夹和三个properties文件也是要我们自己建的,但是 那个Resource Bundle 不用管,这个在yml加上对应配置项自动生成的。 不清楚的继续往下看教学就好)


开始敲(CV)代码:


pom.xml 依赖:


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.68</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


返回码的枚举


CodeEnum.java


/**
 * @author JCccc
 */
public enum CodeEnum {
    SUCCESS(1000, "请求成功"),
    FAIL(2000, "请求失败");
    public final int code;
    public final String msg;
    public Integer getCode() {
        return this.code;
    }
    CodeEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public String getMsg() {
        return this.msg;
    }
}


返回数据的简单封装


ResultData.java


import com.test.myi18n.enums.CodeEnum;
import lombok.Data;
/**
 * @author JCccc
 */
@Data
public class ResultData<T> {
    private Integer code;
    private String message;
    private T data;
    public ResultData(int code, String message) {
        this.code = code;
        this.message = message;
    }
    public static ResultData success(CodeEnum codeEnum) {
        return new ResultData(codeEnum.code, codeEnum.msg);
    }
    public static ResultData success(String msg) {
        return new ResultData(CodeEnum.SUCCESS.getCode(),msg);
    }
}


Locale、 MessageSource的简单方法封装


LocaleMessage.java


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import java.util.Locale;
/**
 * @author JCccc
 */
@Component
public class LocaleMessage {
    @Autowired
    private MessageSource messageSource;
    public String getMessage(String code){
        return this.getMessage(code,new Object[]{});
    }
    public String getMessage(String code,String defaultMessage){
        return this.getMessage(code,null,defaultMessage);
    }
    public String getMessage(String code,String defaultMessage,Locale locale){ return this.getMessage(code,null,defaultMessage,locale); }
    public String getMessage(String code,Locale locale){
        return this.getMessage(code,null,"",locale);
    }
    public String getMessage(String code,Object[] args){ return this.getMessage(code,args,""); }
    public String getMessage(String code,Object[] args,Locale locale){
        return this.getMessage(code,args,"",locale);
    }
    public String getMessage(String code,Object[] args,String defaultMessage){ return this.getMessage(code,args, defaultMessage,LocaleContextHolder.getLocale()); }
    public String getMessage(String code,Object[]args,String defaultMessage,Locale locale){ return messageSource.getMessage(code,args, defaultMessage,locale); }
}


i18n语言转换工具类


I18nUtils.java


import java.util.Locale;
import com.test.myi18n.message.LocaleMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class I18nUtils {
    @Autowired
    private LocaleMessage localeMessage;
    /**
     * 获取key
     *
     * @param key
     * @return
     */
    public  String getKey(String key) {
        String name = localeMessage.getMessage(key);
        return name;
    }
    /**
     * 获取指定哪个配置文件下的key
     *
     * @param key
     * @param local
     * @return
     */
    public  String getKey(String key, Locale local) {
        String name = localeMessage.getMessage(key, local);
        return name;
    }
}


接下来是我们转换的一个关键环节, aop方式拦截 controller接口返回的数据:

 

LanguageAspect.java


import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
 * @author JCccc
 */
@Aspect
@Component
@AllArgsConstructor
@ConditionalOnProperty(prefix = "lang", name = "open", havingValue = "true")
public class LanguageAspect {
    @Autowired
    I18nUtils i18nUtils;
    @Pointcut("execution(* com.test.myi18n.controller.*.*(..)))")
    public void annotationLangCut() {
    }
    /**
     * 拦截controller层返回的结果,修改msg字段
     *
     * @param point
     * @param obj
     */
    @AfterReturning(pointcut = "annotationLangCut()", returning = "obj")
    public void around(JoinPoint point, Object obj) {
        Object resultObject = obj;
        try {
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            //从获取RequestAttributes中获取HttpServletRequest的信息
            HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
            String langFlag = request.getHeader("lang");
            if (null != langFlag) {
                ResultData r = (ResultData) obj;
                String msg = r.getMessage().trim();
                if (StringUtils.isNotEmpty(msg)) {
                    if ("CN".equals(langFlag)) {
                        Locale locale = Locale.CHINA;
                        msg = i18nUtils.getKey(msg, locale);
                    } else if ("EN".equals(langFlag)) {
                        Locale locale = Locale.US;
                        msg = i18nUtils.getKey(msg, locale);
                    } else {
                        msg = i18nUtils.getKey(msg);
                    }
                }
                r.setMessage(msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
            //返回原值
            obj = resultObject;
        }
    }
}


代码简单解读:


1.  annotationLangCut 上面切点管控的地址 需要自己改下,改成自己想管控的文件夹路径


2.  @ConditionalOnProperty 注解,读取yml 里面lang开头的配置项,key为 open ,value 为true


只有为true,这个aop拦截才会生效


3.  String langFlag = request.getHeader("lang");


从这句可以看到我这次文章采取的是让对接接口方(前端)在header里面传入需要使用的语言flag。 例如传入 EN (英文),意思就是需要把提示语转为英文。


大家可以结合自己的项目实际情况,改为从yml读取或者从数据库读取或者从redis读取等等都可以。


4.  ResultData r = (ResultData) obj;

    String msg = r.getMessage().trim();


这两行代码为了就是把拦截到的obj中的message提示语获取出来, 如果大家项目的返回数据不是我文中使用的 ResultData,则需要自己进行魔改调整。


最后是 三份 mess properties文件:


mess.properties  


自定义的返回语= 您好,如果文章对你有用,请关注+收藏+评论


这个文件按照本文里aop的拦截方式,会先检测 当前 的 语言flag值,如果检测不到就h会到


mess.properties 文件里面找。


mess_en_US.properties


1. 请求成功=success
2. 请求失败=fail


mess_zh_CN.properties


1. 请求成功=请求成功
2. 请求失败=请求失败
3. success=请求成功
4. fail=请求失败


最后写个测试接口给大家演示一下效果:

 

    @GetMapping("test")
    public ResultData test(@RequestParam int testNum) {
        if (1==testNum){
            return ResultData.success(CodeEnum.SUCCESS);
        }
        if (2==testNum){
            return ResultData.success(CodeEnum.FAIL);
        }
        if (3==testNum){
            return ResultData.success("自定义的返回语");
        }
        return ResultData.success(CodeEnum.SUCCESS);
    }


调用测试:


 image.pngimage.pngimage.png


好,就先到这。

相关文章
|
11月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——封装统一返回的数据结构
本文介绍了在Spring Boot中封装统一返回的数据结构的方法。通过定义一个泛型类`JsonResult&lt;T&gt;`,包含数据、状态码和提示信息三个属性,满足不同场景下的JSON返回需求。例如,无数据返回时可设置默认状态码&quot;0&quot;和消息&quot;操作成功!&quot;,有数据返回时也可自定义状态码和消息。同时,文章展示了如何在Controller中使用该结构,通过具体示例(如用户信息、列表和Map)说明其灵活性与便捷性。最后总结了Spring Boot中JSON数据返回的配置与实际项目中的应用技巧。
866 0
|
11月前
|
JSON Java fastjson
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——使用 fastJson 处理 null
本文介绍如何使用 fastJson 处理 null 值。与 Jackson 不同,fastJson 需要通过继承 `WebMvcConfigurationSupport` 类并覆盖 `configureMessageConverters` 方法来配置 null 值的处理方式。例如,可将 String 类型的 null 转为 &quot;&quot;,Number 类型的 null 转为 0,避免循环引用等。代码示例展示了具体实现步骤,包括引入相关依赖、设置序列化特性及解决中文乱码问题。
597 0
|
11月前
|
JSON Java fastjson
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——Spring Boot 默认对Json的处理
本文介绍了在Spring Boot中返回Json数据的方法及数据封装技巧。通过使用`@RestController`注解,可以轻松实现接口返回Json格式的数据,默认使用的Json解析框架是Jackson。文章详细讲解了如何处理不同数据类型(如类对象、List、Map)的Json转换,并提供了自定义配置以应对null值问题。此外,还对比了Jackson与阿里巴巴FastJson的特点,以及如何在项目中引入和配置FastJson,解决null值转换和中文乱码等问题。
1588 0
|
XML Java 开发者
Spring Boot中的AOP实现
Spring AOP(面向切面编程)允许开发者在不修改原有业务逻辑的情况下增强功能,基于代理模式拦截和增强方法调用。Spring Boot通过集成Spring AOP和AspectJ简化了AOP的使用,只需添加依赖并定义切面类。关键概念包括切面、通知和切点。切面类使用`@Aspect`和`@Component`注解标注,通知定义切面行为,切点定义应用位置。Spring Boot自动检测并创建代理对象,支持JDK动态代理和CGLIB代理。通过源码分析可深入了解其实现细节,优化应用功能。
621 6
|
前端开发 Java API
SpringBoot整合Flowable【06】- 查询历史数据
本文介绍了Flowable工作流引擎中历史数据的查询与管理。首先回顾了流程变量的应用场景及其局限性,引出表单在灵活定制流程中的重要性。接着详细讲解了如何通过Flowable的历史服务API查询用户的历史绩效数据,包括启动流程、执行任务和查询历史记录的具体步骤,并展示了如何将查询结果封装为更易理解的对象返回。最后总结了Flowable提供的丰富API及其灵活性,为后续学习驳回功能做了铺垫。
1132 0
SpringBoot整合Flowable【06】- 查询历史数据
|
7月前
|
JSON Java 数据格式
Spring Boot返回Json数据及数据封装
在Spring Boot中,接口间及前后端的数据传输通常使用JSON格式。通过@RestController注解,可轻松实现Controller返回JSON数据。该注解是Spring Boot新增的组合注解,结合了@Controller和@ResponseBody的功能,默认将返回值转换为JSON格式。Spring Boot底层默认采用Jackson作为JSON解析框架,并通过spring-boot-starter-json依赖集成了相关库,包括jackson-databind、jackson-datatype-jdk8等常用模块,简化了开发者对依赖的手动管理。
713 3
|
11月前
|
前端开发 Cloud Native Java
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
|
Java 关系型数据库 MySQL
SpringBoot 通过集成 Flink CDC 来实时追踪 MySql 数据变动
通过详细的步骤和示例代码,您可以在 SpringBoot 项目中成功集成 Flink CDC,并实时追踪 MySQL 数据库的变动。
2958 45
|
传感器 机器学习/深度学习 编解码
NEON AOP 表面定向反射率数据是一种高光谱 VSWIR(可见光到短波红外)数据产品,包含 426 个波段
NEON AOP 表面定向反射率数据是高光谱 VSWIR 数据产品,涵盖 426 个波段(380-2510 nm),空间分辨率为 1 米,光谱分辨率为 ~5 纳米。数据由 AVIRIS-NG 传感器收集,包含 QA 波段和大气校正。水蒸气吸收波段设为 -100。数据集适用于环境监测、生态研究等领域。代码示例展示了如何使用 Earth Engine 处理和可视化这些数据。
215 17
|
11月前
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
1506 0