现在越来越多的项目采用前后端分离的技术,当我们想要发生错误时产生如下的格式返回给前端时就要进行异常处理。
code:为错误码。正确时为0.错误时为1
一.定义结果类:
package com.imooc.domain;
/**
* http请求返回的最外层对象
* Created by 廖师兄
* 2017-01-21 13:34
*/
public class Result<T> {
/** 错误码. */
private Integer code;
/** 提示信息. */
private String msg;
/** 具体的内容. */
private T data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
于是controller层返回对像可以定义为Result
controller层:
package com.imooc.controller;
import com.imooc.domain.Girl;
import com.imooc.domain.Result;
import com.imooc.repository.GirlRepository;
import com.imooc.service.GirlService;
import com.imooc.utils.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* Created by 廖师兄
* 2016-11-03 23:15
*/
@RestController
public class GirlController {
private final static Logger logger = LoggerFactory.getLogger(GirlController.class);
@Autowired
private GirlRepository girlRepository;
@Autowired
private GirlService girlService;
/**
* 查询所有女生列表
* @return
*/
@GetMapping(value = "/girls")
public List<Girl> girlList() {
logger.info("girlList");
return girlRepository.findAll();
}
/**
* 添加一个女生
* @return
*/
@PostMapping(value = "/girls")
public Result<Girl> girlAdd(@Valid Girl girl, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return ResultUtil.error(1, bindingResult.getFieldError().getDefaultMessage());
}
girl.setCupSize(girl.getCupSize());
girl.setAge(girl.getAge());
return ResultUtil.success(girlRepository.save(girl));
}
//查询一个女生
@GetMapping(value = "/girls/{id}")
public Girl girlFindOne(@PathVariable("id") Integer id) {
return girlRepository.findOne(id);
}
//更新
@PutMapping(value = "/girls/{id}")
public Girl girlUpdate(@PathVariable("id") Integer id,
@RequestParam("cupSize") String cupSize,
@RequestParam("age") Integer age) {
Girl girl = new Girl();
girl.setId(id);
girl.setCupSize(cupSize);
girl.setAge(age);
return girlRepository.save(girl);
}
//删除
@DeleteMapping(value = "/girls/{id}")
public void girlDelete(@PathVariable("id") Integer id) {
girlRepository.delete(id);
}
//通过年龄查询女生列表
@GetMapping(value = "/girls/age/{age}")
public List<Girl> girlListByAge(@PathVariable("age") Integer age) {
return girlRepository.findByAge(age);
}
@PostMapping(value = "/girls/two")
public void girlTwo() {
girlService.insertTwo();
}
@GetMapping(value = "girls/getAge/{id}")
public void getAge(@PathVariable("id") Integer id) throws Exception{
girlService.getAge(id);
}
}
逻辑:有错误 设置data为null,message设置错误信息,code为1.没有错误,将data里的属性传回,code为0,msg为成功
这里可以看到有很多重复的代码,可以进行代码的优化,可以建立工具类ResultUtil
package com.imooc.utils;
import com.imooc.domain.Result;
public class ResultUtil {
public static Result success(Object object) {
Result result = new Result();
result.setCode(0);
result.setMsg("成功");
result.setData(object);
return result;
}
public static Result success() {
return success(null);
}
public static Result error(Integer code, String msg) {
Result result = new Result();
result.setCode(code);
result.setMsg(msg);
return result;
}
}
若抛出异常,会出现:
解决办法:
进行异常的捕获,取出我们想要的东西,再返回给浏览器
建立异常捕获类:ExceptionHandle
package com.imooc.handle;
import com.imooc.domain.Result;
import com.imooc.exception.GirlException;
import com.imooc.utils.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
public class ExceptionHandle {
private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
if (e instanceof GirlException) {
GirlException girlException = (GirlException) e;
return ResultUtil.error(girlException.getCode(), girlException.getMessage());
}else {
logger.error("【系统异常】{}", e);
return ResultUtil.error(-1, "未知错误");
}
}
}
再次发送请求
缺陷:msg内容有限,不管出现哪种异常code值都是一样的,所以需要我们编写自己的Exception
package com.imooc.exception;
import com.imooc.enums.ResultEnum;
public class GirlException extends RuntimeException{
private Integer code;
public GirlException(ResultEnum resultEnum) {
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
注意:spring框架只有对RuntimeException才会进行事务的回滚,Exception是不会进行事务的回滚。
这时又有一个问题是:code和message都是自己定义。在代码量大的情况下不好进行维护
解决办法:定义枚举
package com.imooc.enums;
public enum ResultEnum {
UNKONW_ERROR(-1, "未知错误"),
SUCCESS(0, "成功"),
PRIMARY_SCHOOL(100, "我猜你可能还在上小学"),
MIDDLE_SCHOOL(101, "你可能在上初中"),
;
private Integer code;
private String msg;
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
回顾步骤:
1.先固定了格式
2.默认的Exception只接受message,但我们还有code,采用自定义的异常类进行处理
3.有了异常需哟捕获,所以我们又定义捕获异常的类
4.最后定义枚举类,对code,message来统一管理