Spring Boot+国际化+统一处理异常+统一处理控制器返回结果

源码地址:https://github.com/Jieszs/springboot-2.x-learning

思路:

拦截后端的异常和控制器的返回结果,根据前端的请求头,选择该国语言的文本内容,实现国际化

步骤:

1.引入依赖:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

2.文件结构:

3.拦截全局异常,自定义异常

/**
 * @author zj
 * @date 2019/11/4
 * 全局异常处理
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    @Resource
    private InternationalUtil internationalUtil;

    /**
     * 400,用来处理bean字段异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity resolveConstraintViolationException(ConstraintViolationException ex) {
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        if (!CollectionUtils.isEmpty(constraintViolations)) {
            StringBuilder msgBuilder = new StringBuilder();
            for (ConstraintViolation constraintViolation : constraintViolations) {
                msgBuilder.append(constraintViolation.getMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if (errorMessage.length() > 1) {
                errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
            }
            return buildResponse(errorMessage, HttpStatus.BAD_REQUEST);
        }
        return buildResponse(ex.getMessage(), HttpStatus.BAD_REQUEST);
    }

    /**
     * 400,用来处理方法参数异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        List<ObjectError> objectErrors = ex.getBindingResult().getAllErrors();
        if (!CollectionUtils.isEmpty(objectErrors)) {
            StringBuilder msgBuilder = new StringBuilder();
            for (ObjectError objectError : objectErrors) {
                msgBuilder.append(objectError.getDefaultMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if (errorMessage.length() > 1) {
                errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
            }
            return buildResponse(errorMessage, HttpStatus.BAD_REQUEST);

        }
        return buildResponse(ex.getMessage(), HttpStatus.BAD_REQUEST);
    }

    /**
     * 400
     *
     * @param e
     * @return
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity handleIllegalArgumentException(Exception e) {
        return buildResponse(e.getMessage(), HttpStatus.BAD_REQUEST);
    }

    /**
     * 403
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity handleBusinessException(Exception e) {
        return buildResponse(e.getMessage(), HttpStatus.FORBIDDEN);
    }


    /**
     * 构建响应实体
     *
     * @param msg
     * @param status
     * @return
     */
    private ResponseEntity buildResponse(String msg, HttpStatus status) {
        return buildResponse(msg, status, null);
    }

    /**
     * 构建响应实体
     *
     * @param msg
     * @param status
     * @return
     */
    private ResponseEntity buildResponse(String msg, HttpStatus status, String result) {
        JSONObject body = new JSONObject();
        body.put("status", status.value());
        body.put("error", status);
        body.put("message", internationalUtil.getInterNationalMsg(msg));
        return new ResponseEntity(body, status);
    }
}
/**
 * @author zj
 * @date 2019/11/4
 * 业务异常
 */
public class BusinessException extends Exception {
    public BusinessException(String message) {
        super(message);
    }
}

4.拦截控制器

/**
 * @author zj
 * @date 2019/11/4
 * 全局控制器处理
 */
@ControllerAdvice
public class ResponseBodyInterceptor implements ResponseBodyAdvice {

    @Resource
    private InternationalUtil internationalUtil;

    @Override
    public boolean supports(MethodParameter methodParameter, Class aClass) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        //控制器结果为字符串才进行处理
        if (body instanceof String) {
            return internationalUtil.getInterNationalMsg((String)body);
        }
        return body;
    }
}

5.国际化工具类


/**
 * 国际化工具类
 * @author zj
 * @date 2019/11/4
 */
@Component
public class InternationalUtil {
    @Resource
    private HttpServletRequest request;

    private static final String ACCEPT_LANGUAGE ="Accept-Language";
    private static final String FILTER_PREFIX ="#";
    private static final String LANGUAGE_SEPARATOR ="-";
    /**
     * 获取国际化消息
     * @param key 国际化的key
     * @param args 被替换占位符的值
     * 1.带#号的不是key的字符串,直接过滤#号
     * 2.是key的字符串,有占位符的替换
     * 3.不是key的字符串,返回字符串本身
     *
     */
    public  String getInterNationalMsg(String key, Object... args) {
        //带#号的不是key的字符串,直接过滤#号
        if (key.startsWith(FILTER_PREFIX)) {
            return key.substring(1);
        }
        ResourceBundle rb;
        String requestHeader = request.getHeader(ACCEPT_LANGUAGE);
        //是key的字符串,有占位符的替换
        try {
            //如en-US,zh-CN
            if (!StringUtils.isEmpty(requestHeader) && requestHeader.contains(LANGUAGE_SEPARATOR)) {
                rb = ResourceBundle.getBundle("msg", new Locale(requestHeader.split(LANGUAGE_SEPARATOR)[0], requestHeader.split(LANGUAGE_SEPARATOR)[1]));
            } else {
                rb = ResourceBundle.getBundle("msg");
            }
            return MessageFormat.format(rb.getString(key), args);
        } catch (Exception e) {
            //不是key的字符串,返回字符串本身
            return key;
        }
    }
}

6.Resource Bundle

接着

编辑

编辑

7.测试

控制器

/**
 * @author zj
 * @date 2019/11/4
 */
@RestController
public class HelloController {
    @Resource
    private InternationalUtil internationalUtil;

    /**
     * 测试控制器结果国际化
     *
     * @return
     */
    @RequestMapping("/hello")
    public String hello() {
        return "HELLO_WORLD";
    }

    /**
     * 测试异常国际化
     *
     * @return
     */
    @RequestMapping("/exception")
    public void exception() throws BusinessException {
        throw new BusinessException("BUSINESS_EXCEPTION");
    }

    /**
     * 测试不国际化
     *
     * @return
     */
    @RequestMapping("/helloFilter")
    public String helloFilter() {
        return "#hello world!";
    }

    /**
     * 测试占位符
     *
     * @return
     */
    @RequestMapping("/helloUser")
    public String helloUser(String name) {
        return internationalUtil.getInterNationalMsg("HELLO_USER",name);
    }
}

Resource bundle

BUSINESS_EXCEPTION=Business exception!
HELLO_USER=hello,{0}!
HELLO_WORLD=hello world!
BUSINESS_EXCEPTION=\u4e1a\u52a1\u5f02\u5e38\uff01
HELLO_USER=\u7528\u6237\u007b\u0030\u007d\u002c\u4f60\u597d\uff01
HELLO_WORLD=\u4f60\u597d\uff0c\u4e16\u754c\uff01

测试结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值