Home  >  Article  >  Java  >  How Springboot+AOP implements internationalization of return data prompts

How Springboot+AOP implements internationalization of return data prompts

WBOY
WBOYforward
2023-05-29 15:45:331319browse

Text

First look at the project directory structure of this sample teaching:

How Springboot+AOP implements internationalization of return data prompts

(Of course, the i18n folder and three properties files in the resource are also We need to build it ourselves, but we don’t need to worry about the Resource Bundle. This is automatically generated by adding the corresponding configuration items to the yml. If you are not sure, just continue to read the tutorial)

Start typing (CV) code:

pom.xml Dependencies:

<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>

Return code enumeration

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;
    }
}

Return data Simple encapsulation

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's simple method encapsulation

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 Language Conversion Tool Class

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;
    }
}

The next step is a key step in our conversion. The aop method intercepts the data returned by the controller interface:

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;
        }
    }
}

Simple interpretation of the code:

1. The address of the annotationLangCut cutoff control needs to be changed by yourself to the folder you want to control. Path

2. @ConditionalOnProperty annotation, read the configuration items starting with lang in the yml, the key is open, the value is true

Only if it is true, this aop interception will take effect

3. String langFlag = request.getHeader("lang");
You can see from this sentence that what I adopted in this article is to let the docking interface party (front-end) pass in the language flag that needs to be used in the header. For example, passing in EN (English) means that the prompt language needs to be converted into English.

You can combine the actual situation of your project and change it to read from yml or read from the database or read from redis, etc.

4. ResultData r = (ResultData) obj;
String msg = r.getMessage().trim();

The purpose of these two lines of code is to put the intercepted obj into Get the message prompt. If the return data of your project is not the ResultData used in my article, you need to make magic adjustments yourself.

Finally, there are three mess properties files:

mess.properties

Customized return language = Hello, if the article is useful to you, Please pay attention to the favorite comments

This file will first detect the current language flag value according to the aop interception method in this article. If it is not detected, it will be found in the
mess.properties file.

mess_en_US.properties

Request success=success
Request failure=fail

mess_zh_CN.properties

Request success = Request success
Request failure = Request failure
success = Request success
fail = Request failure

Finally write a test interface to demonstrate the effect for everyone:

 @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);
    }

Call test:

How Springboot+AOP implements internationalization of return data prompts

How Springboot+AOP implements internationalization of return data prompts

How Springboot+AOP implements internationalization of return data prompts

The above is the detailed content of How Springboot+AOP implements internationalization of return data prompts. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete