栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

浅谈springmvc 通过异常增强返回给客户端统一格式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

浅谈springmvc 通过异常增强返回给客户端统一格式

在springmvc开发中,我们经常遇到这样的问题;逻辑正常执行时返回客户端指定格式的数据,比如json,但是遇NullPointerException空指针异常,NoSuchMethodException调用的方法不存在异常,返回给客户端的是服务端异常堆栈信息,导致客户端不能正常解析数据;这明显不是我们想要的。

幸好从spring3.2提供的新注解@ControllerAdvice,从名字上可以看出大体意思是控制器增强。原理是使用AOP对Controller控制器进行增强(前置增强、后置增强、环绕增强,AOP原理请自行查阅);那么我没可以自行对控制器的方法进行调用前(前置增强)和调用后(后置增强)的处理。

spring提供了@ExceptionHandler异常增强注解。程序如果在执行控制器方法前或执行时抛出异常,会被@ExceptionHandler注解了的方法处理。

配置applicationContext-mvc.xml:



  
  
  
  

全局异常处理类:

package com.drskj.apiservice.handler;
import java.io.IOException;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import com.drskj.apiservice.common.utils.ReturnFormat;

@ControllerAdvice
public class RestExceptionHandler{
  //运行时异常
  @ExceptionHandler(RuntimeException.class) 
  @ResponseBody 
  public String runtimeExceptionHandler(RuntimeException runtimeException) { 
    return ReturnFormat.retParam(1000, null);
  } 
  //空指针异常
  @ExceptionHandler(NullPointerException.class) 
  @ResponseBody 
  public String nullPointerExceptionHandler(NullPointerException ex) { 
    ex.printStackTrace();
    return ReturnFormat.retParam(1001, null);
  }  
  //类型转换异常
  @ExceptionHandler(ClassCastException.class) 
  @ResponseBody 
  public String classCastExceptionHandler(ClassCastException ex) { 
    ex.printStackTrace();
    return ReturnFormat.retParam(1002, null); 
  } 
  //IO异常
  @ExceptionHandler(IOException.class) 
  @ResponseBody 
  public String iOExceptionHandler(IOException ex) { 
    ex.printStackTrace();
    return ReturnFormat.retParam(1003, null); 
  } 
  //未知方法异常
  @ExceptionHandler(NoSuchMethodException.class) 
  @ResponseBody 
  public String noSuchMethodExceptionHandler(NoSuchMethodException ex) { 
    ex.printStackTrace();
    return ReturnFormat.retParam(1004, null);
  } 
  //数组越界异常
  @ExceptionHandler(IndexOutOfBoundsException.class) 
  @ResponseBody 
  public String indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) { 
    ex.printStackTrace();
    return ReturnFormat.retParam(1005, null);
  }
  //400错误
  @ExceptionHandler({HttpMessageNotReadableException.class})
  @ResponseBody
  public String requestNotReadable(HttpMessageNotReadableException ex){
    System.out.println("400..requestNotReadable");
    ex.printStackTrace();
    return ReturnFormat.retParam(400, null);
  }
  //400错误
  @ExceptionHandler({TypeMismatchException.class})
  @ResponseBody
  public String requestTypeMismatch(TypeMismatchException ex){
    System.out.println("400..TypeMismatchException");
    ex.printStackTrace();
    return ReturnFormat.retParam(400, null);
  }
  //400错误
  @ExceptionHandler({MissingServletRequestParameterException.class})
  @ResponseBody
  public String requestMissingServletRequest(MissingServletRequestParameterException ex){
    System.out.println("400..MissingServletRequest");
    ex.printStackTrace();
    return ReturnFormat.retParam(400, null);
  }
  //405错误
  @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
  @ResponseBody
  public String request405(){
    System.out.println("405...");
    return ReturnFormat.retParam(405, null);
  }
  //406错误
  @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
  @ResponseBody
  public String request406(){
    System.out.println("404...");
    return ReturnFormat.retParam(406, null);
  }
  //500错误
  @ExceptionHandler({ConversionNotSupportedException.class,HttpMessageNotWritableException.class})
  @ResponseBody
  public String server500(RuntimeException runtimeException){
    System.out.println("500...");
    return ReturnFormat.retParam(406, null);
  }
}

以上包括了常见的服务端异常类型,@ResponseBody表示以json格式返回客户端数据。我们也可以自定义异常类(这里我把它叫做MyException)并且继承RunTimeException,并且在全局异常处理类新增一个方法来处理异常,使用@ExceptionHandler(MyException.class)注解在方法上实现自定义异常增强。

格式化response数据类ReturnFormat:

package com.drskj.apiservice.common.utils;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;import com.google.common.collect.Maps;
//格式化返回客户端数据格式(json)
public class ReturnFormat {
  private static MapmessageMap = Maps.newHashMap();
  //初始化状态码与文字说明
  static {
    messageMap.put("0", "");
    messageMap.put("400", "Bad Request!");
    messageMap.put("401", "NotAuthorization");
    messageMap.put("405", "Method Not Allowed");
    messageMap.put("406", "Not Acceptable");
    messageMap.put("500", "Internal Server Error");
    messageMap.put("1000", "[服务器]运行时异常");
    messageMap.put("1001", "[服务器]空值异常");
    messageMap.put("1002", "[服务器]数据类型转换异常");
    messageMap.put("1003", "[服务器]IO异常");
    messageMap.put("1004", "[服务器]未知方法异常");
    messageMap.put("1005", "[服务器]数组越界异常");
    messageMap.put("1006", "[服务器]网络异常");
    messageMap.put("1010", "用户未注册");
    messageMap.put("1011", "用户已注册");
    messageMap.put("1012", "用户名或密码错误");
    messageMap.put("1013", "用户帐号冻结");
    messageMap.put("1014", "用户信息编辑失败");
    messageMap.put("1015", "用户信息失效,请重新获取");
    messageMap.put("1020", "验证码发送失败");
    messageMap.put("1021", "验证码失效");
    messageMap.put("1022", "验证码错误");
    messageMap.put("1023", "验证码不可用");
    messageMap.put("1029", "短信平台异常");
    messageMap.put("1030", "周边无店铺");
    messageMap.put("1031", "店铺添加失败");
    messageMap.put("1032", "编辑店铺信息失败");
    messageMap.put("1033", "每个用户只能添加一个商铺");
    messageMap.put("1034", "店铺不存在");
    messageMap.put("1040", "无浏览商品");
    messageMap.put("1041", "添加失败,商品种类超出上限");
    messageMap.put("1042", "商品不存在");
    messageMap.put("1043", "商品删除失败");
    messageMap.put("2010", "缺少参数或值为空");
    
    messageMap.put("2029", "参数不合法");
    messageMap.put("2020", "无效的Token");
    messageMap.put("2021", "无操作权限");
    messageMap.put("2022", "RSA解密失败,密文数据已损坏");
    messageMap.put("2023", "请重新登录");
  }
  public static String retParam(int status,Object data) {
    OutputJson json = new OutputJson(status, messageMap.get(String.valueOf(status)), data);
    return json.toString();
  }
}

返回格式实体类OutPutJson;这里用到了知名的fastjson将对象转json:

package com.drskj.apiservice.common.utils;
import java.io.Serializable;
import com.alibaba.fastjson.JSON;
public class OutputJson implements Serializable{
  
  private static final long serialVersionUID = 1L;
  //状态码
  private int status;
  //必要的提示信息
  private String message;
  //业务数据
  private Object data;
  public OutputJson(int status,String message,Object data){
    this.status = status;
    this.message = message;
    this.data = data;
  }
  public int getStatus() {
    return status;
  }
  public void setStatus(int status) {
    this.status = status;
  }
  public String getMessage() {
    return message;
  }
  public void setMessage(String message) {
    this.message = message;
  }
  public Object getData() {
    return data;
  }
  public void setData(Object data) {
    this.data = data;
  }
  public String toString(){
    if(null == this.data){
      this.setData(new Object());
    }
    return JSON.toJSonString(this);
  }
}

实例:CodeController继承自baseController,有一个sendMessage方法调用Service层发送短信验证码;

1.如果客户端请求方式为非POST,否则抛出HttpMediaTypeNotSupportedException异常;

2.如果username、forType或userType没传,则抛出MissingServletRequestParameterException异常;

3.如果springmvc接收无法进行类型转换的字段,会报TypeMismatchException异常;

.....

大部分的请求异常,springmvc已经为我们定义好了,为我们开发restful应用提高了测试效率,方便排查问题出在哪一环节。

@RestController@RequestMapping("/api/v1/code")
public class CodeController extends baseController {
  @Autowired
  private CodeService codeService;
  
  
  @RequestMapping(value="/sendMessage",method=RequestMethod.POST,produces="application/json")
  public String sendMessage(@RequestParam(value="username",required=true)String username,
      @RequestParam(value="forType",required=true)String forType,
      @RequestParam(value="userType",required=true)String userType){
    if(null == username || "".equals(username)){
      return retContent(2010, null);
    }
    if(!"user".equals(userType) && !"merchant".equals(userType)){
      return retContent(2029, null);
    }
    if(!"register".equals(forType) && !"backpwd".equals(forType)){
      return retContent(2029, null);
    }
    return codeService.sendMessage(username, forType, userType);
  }
}
public abstract class baseController {
  protected String retContent(int status,Object data) {
    return ReturnFormat.retParam(status, data);
  }
}

最终,不管是正常的业务逻辑还是服务端异常,都会调用ReturnFormat.retParam(int status,Object data)方法返回格式统一的数据。

以上这篇浅谈springmvc 通过异常增强返回给客户端统一格式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/131443.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号