表单验证
修改Girl类:
@NotBlank(message = "这个字段必传")
private String cupSize;
@Min(value = 18, message = "未成年少女禁止入内")
private Integer age;
@NotNull(message = "金额必传")
private Double money;
修改PUT方法:
@PostMapping(value = "/girls")
public Girl girlAdd(@Valid Girl girl, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
System.out.println(bindingResult.getFieldError().getDefaultMessage());
return null;
}
girl.setCupSize(girl.getCupSize());
girl.setAge(girl.getAge());
return girlRepository.save(girl);
}
AOP统一处理请求日志
AOP是一种编程范式,与语言无关,是一种程序设计思想
面向切面(AOP)Aspect Oriented Programming,利用横切技术,将面向对象构建的庞大的类的体系进行水平的切割,并且会将那些影响到了多个类的公共行为封装成一个可重用模块,这个模块称为切面。(将通用逻辑从业务逻辑中分离出来)
面向对象(OOP)Object Oriented Programming,将需求功能垂直划分为不同的并且相对独立的,会封装成良好的类并且让它们有属于自己的行为
面向过程(POP)Procedure Oriented Programming
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
@Aspect
@Component
public class HttpAspect {
@Before("execution(public * com.imooc.controller.GirlController.*(..))")
public void log() {
System.out.println(111111111);
}
@After("execution(public * com.imooc.controller.GirlController.*(..))")
public void doAfter() {
System.out.println(222222222);
}
}
改良:
@Aspect
@Component
public class HttpAspect {
@Pointcut("execution(public * com.imooc.controller.GirlController.*(..))")
public void log() {
}
@Before("log()")
public void doBefore() {
System.out.println(11111111);
}
@After("log()")
public void doAfter() {
System.out.println(222222222);
}
}
使用Logger:
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = Logger.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.imooc.controller.GirlController.*(..))")
public void log() {
}
@Before("log()")
public void doBefore() {
logger.info("1111111");
}
@After("log()")
public void doAfter() {
logger.info("2222222");
}
}
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.imooc.controller.GirlController.*(..))")
public void log() {
}
@Before("log()")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//url
logger.info("url={}", request.getRequestURL());
//method
logger.info("method={}", request.getMethod());
//ip
logger.info("ip={}", request.getRemoteAddr());
//类方法
logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//参数
logger.info("args={}", joinPoint.getArgs());
}
@After("log()")
public void doAfter() {
logger.info("2222222");
}
@AfterReturning(returning = "object",pointcut = "log()")
public void doAfterReturning(Object object) {
logger.info("response={}", object);
}
}
统一异常处理
/**
* http请求返回的最外层对象
*/
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;
}
}
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;
}
}
@PostMapping(value = "/girls")
public Result 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));
}
GirlService:
public void getAge(Integer id) throws Exception {
Girl girl = girlRepository.findOne(id);
Integer age = girl.getAge();
if (age < 10 ) {
throw new Exception("你还在上小学吧");
} else if (age > 10 && age < 16) {
throw new Exception("你可能在上初中");
}
}
Controller:
@GetMapping(value = "girls/getAge/{id}")
public void getAge(@PathVariable("id") Integer id) throws Exception {
girlService.getAge(id);
}
@ControllerAdvice
public class ExceptionHandle {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e) {
return ResultUtil.error(100, e.getMessage());
}
}
定义带有错误码的异常
自定义异常:
//抛出Exception是不会进行事务回滚的
public class GirlException extends RuntimeException {
private Integer code;
public GirlException(Integer code, String message) {
super(message);
this.code = code;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
@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, "未知错误");
}
}
}
统一管理错误码和提示
修改GirlException:
public GirlException(ResultEnum resultEnum) {
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
}
修改GirlService:
public void getAge(Integer id) throws Exception {
Girl girl = girlRepository.findOne(id);
Integer age = girl.getAge();
if (age < 10 ) {
throw new GirlException(ResultEnum.PRIMARY_SCHOOL);
} else if (age > 10 && age < 16) {
throw new GirlException(ResultEnum.MIDDLE_SCHOOL);
}
}
添加ResultEnum:
public enum ResultEnum {
UNKONW_ERROR(-1, "未知错误"),
SUCCDESS(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;
}
}
单元测试
GirlService:
public Girl findOne(Integer id) {
return girlRepository.findOne(id);
}
测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
public class GirlServiceTest {
@Autowired
private GirlService girlService;
@Test
public void findOneTest() {
Girl girl = girlService.findOne(11);
Assert.assertEquals(new Integer(10), girl.getAge());
}
}/*
java.lang.AssertionError:
Expected :10
Actual :9
*/
使用IDEA自带功能
Controller测试
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class GirlControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void girlList() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/girls"))
.andExpect(MockMvcResultMatchers.status().isOk());
//.andExpect(MockMvcResultMatchers.content().string("abc"));
}
}
在项目打包时会自动执行单元测试。
跳过单元测试:mvn clean package -Dmaven.test.ship=true