使用@Min(value=18,message="未成年少女金之入内")
标记对应类中的属性。注解表示age最小值为18,错误提示为:未成年少女禁止入内
Girl类实例代码
package com.study.demo.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.Min;
@Entity
public class Girl{
@Id
@GeneratedValue
private Integer id;
private String cupSize;
//表示age最小值为18,错误提示为:未成年少女禁止入内
@Min(value=18,message = "未成年少女禁止入内")
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCupSize() {
return cupSize;
}
public void setCupSize(String cupSize) {
this.cupSize = cupSize;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Girl{" +
"id=" + id +
", cupSize='" + cupSize + '\'' +
", age=" + age +
'}';
}
}
结果对象的hasErrors()方法用于判断是否发生错误
结果对象的getFieldError().getDefaultMessage()方法获得对应的错误信息
对应方法的实例代码
//新增女生
@PostMapping(value="/girls")
public Girl girlAdd(@Valid Girl girl, BindingResult bindingResult){//@Valid注解表示要验证的对象为girl,验证结果会返回到参数bindingResult对象中
//通过对象的hasErrors()方法获得是否发生错误
if(bindingResult.hasErrors()){
//并通过getFieldError().getDefaultMessage()方法获得对应的错误信息
System.out.println(bindingResult.getFieldError().getDefaultMessage());
return null;
}
girl.setCupSize(girl.getCupSize());
girl.setAge(girl.getAge());
return girlRepository.save(girl);//方法返回的就是添加的对象
}
当发送post请求时,若cupSize属性超过18则会在控制台输出“未成年少女禁止入内”,并返回null值
收到HttpRequest请求
—> 记录请求
—> 处理网络请求
—> 生成HttpResponse
—> 记录回复
收到数据库操作请求
—> 记录请求
—> 增删改查
—> 生成处理结果
—> 记录回复
添加依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
建立处理文件:aspect/HttpAspect.java
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect//标记类为Aspect类
@Component//引入到Spring容器中
public class HttpAspect {
//org.slf4j.Logger是Spring自带的日志记录框架
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.study.demo.controller.HelloController.girlList(..))")//.girlList(..)表示girlList方法不管是任何参数都会被拦截;.*(..)则表示该类的所有方法都会被拦截
public void log(){
}
//定义在http请求到方法之前将内容记录下来
@Before("log()")
public void doBefore(){
logger.info("记录日志");//使用Logger的方法记录日志
}
//定义在执行完方法后调用
@After("log()")
public void doAfter(){
logger.info("执行方法之后的调用...");
}
}
访问接口时的显示内容(可以看出使用logger.info()
方法打印的内容带有时间等相关信息)
2018-09-19 12:58:55.250 INFO 44464 --- [nio-8082-exec-2] com.study.demo.aspect.HttpAspect : 记录日志
2018-09-19 12:58:55.253 INFO 44464 --- [nio-8082-exec-2] c.study.demo.controller.HelloController : 执行到GirlList
2018-09-19 12:58:55.280 INFO 44464 --- [nio-8082-exec-2] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select girl0_.id as id1_0_, girl0_.age as age2_0_, girl0_.cup_size as cup_size3_0_ from girl girl0_
2018-09-19 12:58:55.364 INFO 44464 --- [nio-8082-exec-2] com.study.demo.aspect.HttpAspect : 执行方法之后的调用...
调整@Before注解的方法执行指定内容
@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());
//请求的类方法,通过当前类的参数传入的JoinPoint对象获取对应的内容
//joinPoint.getSignature().getDeclaringTypeName()获取的是类名
//joinPoint.getSignature().getName()获取类方法名
logger.info("class_method={}",joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
//参数
logger.info("args={}",joinPoint.getArgs());
}
通过@AfterReturning
注解获得方法返回的内容
//参数1为方法的入参变量名,参数2为使用的连接点方法名
@AfterReturning(returning="object",pointcut="log()")
//返回的内容可以是很多,但是对于程序而言他们都是对象
public void doAfterReturning(Object object){
logger.info("response={}",object);
}
访问接口时显示的内容
2018-09-19 13:20:31.876 INFO 44599 --- [nio-8082-exec-1] com.study.demo.aspect.HttpAspect : url=http://localhost:8082/girls
2018-09-19 13:20:31.876 INFO 44599 --- [nio-8082-exec-1] com.study.demo.aspect.HttpAspect : method=GET
2018-09-19 13:20:31.876 INFO 44599 --- [nio-8082-exec-1] com.study.demo.aspect.HttpAspect : ip=0:0:0:0:0:0:0:1
2018-09-19 13:20:31.878 INFO 44599 --- [nio-8082-exec-1] com.study.demo.aspect.HttpAspect : class_method=com.study.demo.controller.HelloController.girlList
2018-09-19 13:20:31.878 INFO 44599 --- [nio-8082-exec-1] com.study.demo.aspect.HttpAspect : args={}
2018-09-19 13:20:31.882 INFO 44599 --- [nio-8082-exec-1] c.study.demo.controller.HelloController : 执行到GirlList
2018-09-19 13:20:31.911 INFO 44599 --- [nio-8082-exec-1] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select girl0_.id as id1_0_, girl0_.age as age2_0_, girl0_.cup_size as cup_size3_0_ from girl girl0_
2018-09-19 13:20:31.991 INFO 44599 --- [nio-8082-exec-1] com.study.demo.aspect.HttpAspect : 执行方法之后的调用...
2018-09-19 13:20:31.991 INFO 44599 --- [nio-8082-exec-1] com.study.demo.aspect.HttpAspect : response=[]
定义统一异常返回对象/src/main/java/com/study/demo/domain/Result.java
package com.study.demo.domain;
/**
* 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;
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
定义错误对象生成工具方法/src/main/java/com/study/demo/utils/ResultUtil.java
package com.study.demo.utils;
import com.study.demo.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);
result.setData(null);
return result;
}
}
自定义异常,用于传递对应的错误编号/src/main/java/com/study/demo/exception/GirlException.java
package com.study.demo.exception;
import com.study.demo.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;
}
}
定义异常处理内容,在方法抛出异常时执行的对应处理方法/src/main/java/com/study/demo/handle/ExceptionHandle.java
package com.study.demo.handle;
import com.study.demo.domain.Result;
import com.study.demo.exception.GirlException;
import com.study.demo.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 {
public static final Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
//声明要捕获哪个异常类
@ExceptionHandler(value = Exception.class)
//由于要返回的是一个json,但是类上方又没有@RestController注解,故需要用ResponseBody修饰
@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,"未知错误");
}
}
}
在Controller中添加判断对象年龄并抛出异常测试方法/src/main/java/com/study/demo/controller/HelloController.java
package com.study.demo.controller;
import com.study.demo.domain.Girl;
import com.study.demo.domain.Result;
import com.study.demo.repository.GirlRepository;
import com.study.demo.service.GirlService;
import com.study.demo.utils.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.Optional;
@RestController
public class HelloController {
public final static Logger logger = LoggerFactory.getLogger(HelloController.class);
@Autowired
private GirlRepository girlRepository;
@Autowired
public GirlService girlService;
//查询所有女生列表
@GetMapping(value="/girls")
public List<Girl> girlList(){
logger.info("执行到GirlList");
return girlRepository.findAll();
}
//新增女生
@PostMapping(value="/girls")
public Result girlAdd(@Valid Girl girl, BindingResult bindingResult){//@Valid注解表示要验证的对象为girl,验证结果会返回到参数bindingResult对象中
//通过对象的hasErrors()方法获得是否发生错误
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 Optional<Girl> girlFindOne(@PathVariable("id")Integer id){
Optional<Girl> girl = girlRepository.findById(id);
return girl;
}
//更新
@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.deleteById(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);
}
}
在service中添加对应处理方法,针对不同情况的age内容抛出不同错误码的异常/src/main/java/com/study/demo/service/GirlService.java
package com.study.demo.service;
import com.study.demo.domain.Girl;
import com.study.demo.enums.ResultEnum;
import com.study.demo.exception.GirlException;
import com.study.demo.repository.GirlRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
@Service
public class GirlService {
@Autowired
private GirlRepository girlRepository;
//添加@Transactional事务注解
@Transactional
public void insertTwo(){
Girl girlA = new Girl();
girlA.setCupSize("A");
girlA.setAge(18);
girlRepository.save(girlA);
Girl girlB = new Girl();
girlB.setCupSize("Fffffff");
girlB.setAge(19);
girlRepository.save(girlB);
}
public void getAge(Integer id) throws GirlException{
Optional<Girl> girl = girlRepository.findById(id);
Integer age = girl.get().getAge();
if(age<10){
//返回你还在上小学吧——使用枚举的形式获得
throw new GirlException(ResultEnum.PRIMARY_SCHOOL);
}else if(age>=10&&age<16){
//返回你可能在上初中
throw new GirlException(ResultEnum.MIDDLE_SCHOOL);
}
}
}
定义枚举类型,将错误编号与错误信息统一管理/src/main/java/com/study/demo/enums/ResultEnum.java
package com.study.demo.enums;
//使用枚举将错误编号与错误信息统一管理
public enum ResultEnum {
UNKOWN_ERROR(-1,"未知错误"),
SUCCESS(0,"成功"),
PRIMARY_SCHOOL(100,"你可能在上小学~"),
MIDDLE_SCHOOL(101,"你可能在上初中~")
;
private Integer code;
private String msg;
//枚举的使用基本上不用set方法,而使用构造方法
ResultEnum(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
/src/test/java/com/study/demo/GirlServiceTest.java
文件编写findOneTest方法进行测试在GirlService中编写需要测试的方法
package com.study.demo.service;
import com.study.demo.domain.Girl;
import com.study.demo.enums.ResultEnum;
import com.study.demo.exception.GirlException;
import com.study.demo.repository.GirlRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
@Service
public class GirlService {
@Autowired
private GirlRepository girlRepository;
//添加@Transactional事务注解
@Transactional
public void insertTwo(){
Girl girlA = new Girl();
girlA.setCupSize("A");
girlA.setAge(18);
girlRepository.save(girlA);
Girl girlB = new Girl();
girlB.setCupSize("Fffffff");
girlB.setAge(19);
girlRepository.save(girlB);
}
public void getAge(Integer id) throws GirlException{
Optional<Girl> girl = girlRepository.findById(id);
Integer age = girl.get().getAge();
if(age<10){
//返回你还在上小学吧
throw new GirlException(ResultEnum.PRIMARY_SCHOOL);
}else if(age>=10&&age<16){
//返回你可能在上初中
throw new GirlException(ResultEnum.MIDDLE_SCHOOL);
}
}
/**
* 通过Id查询一个女生的信息
*/
public Optional<Girl> findOne(Integer id){
return girlRepository.findById(id);
}
}
编写GirlServiceTest方法进行测试(右击Run on findOneTest
进行执行)
package com.study.demo;
import com.study.demo.domain.Girl;
import com.study.demo.service.GirlService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Optional;
//表示当前是在测试环节里面跑的,底层使用JUnit测试工具
@RunWith(SpringRunner.class)
//将启动整个Spring的工程
@SpringBootTest
public class GirlServiceTest {
@Autowired
private GirlService girlService;
@Test
public void findOneTest(){
Optional<Girl> girl = girlService.findOne(4);
//断言的方式判断,要求参数都是Object
Assert.assertEquals(new Integer(16),girl.get().getAge());
}
}
右击 -> Go To -> Test ->Create new Test -> 选择要测试的方法 -> OK
使用IDEA执行右击 -> Go To -> Test ->Create new Test -> 选择要测试的方法 -> OK
生成对应的测试文件
在测试文件类上不仅要添加@RunWith(SpringRunner.class)和@SpringBootTest
注解,还要添加@AutoConfigurationMockMvc
注解标注是controller的测试类,并使用MockMvc对象的perform方法进行相关测试内容的设置
package com.study.demo.controller;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import static org.junit.Assert.*;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void girlList() throws Exception{
mvc.perform(MockMvcRequestBuilders.get("/girls"))//Get方法,请求地址为/girls
.andExpect(MockMvcResultMatchers.status().isOk())//表示期望返回的状态码为200
.andExpect(MockMvcResultMatchers.content().string("abc"));//表示期望返回的是abc字符串
}
}
mvn clean package
进行打包的时候会自动执行对应的单元测试mvn clean package -Dmaven.test.skip=true
跳过单元测试