示例代码:https://git.oschina.net/liaoshixiong/girl
1、使用@Valid表单验证
2、使用AOP处理请求
3、异常处理
4、测试代码:单元测试。
表单验证
1、代码使用GIT下载命令
// 下载代码
git clone git@git.oschina.net:liaoshixiong/girl.git
// 切换到标签所在的代码
git checkout -b web-2 web-2
// 切换到标签所在的代码
git checkout -b web-1 web-1
2、添加一个记录,可以使用实体类来获取所有的参数
GirlController.java
/**
* 添加一个女生
* @return
*/
@PostMapping(value = "/girls")
public Girl girlAdd(Girl girl){
return this.girRepository.save(girl);
}
3、表单验证:age<18,不能添加。
在实体类中写注解。Girl.java
@Min(value=18,message = "未成年少女禁止")
private Integer age;
在controller中写对应的验证注解。GirlController.java
/**
* 添加一个女生
* @return
*/
@PostMapping(value = "/girls")
public Girl girlAdd(@Valid Girl girl, BindingResult bindingResult){
if(bindingResult.hasErrors()){
System.out.println(bindingResult.getFieldError().getDefaultMessage());
return null;
}
return this.girRepository.save(girl);
}
使用AOP处理请求
AOP:
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程。
OOP:面向对象程序设计(Object Oriented Programming)
统一处理请求日志。
1、添加依赖到pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、编写代码:Before(...)拦截所有GirlContoller下的方法,在之前都执行log().
After(...)拦截所有GirlContoller下的方法,在之后都执行log().
@Aspect
@Component
public class HttpAspect {
@Before("execution(public * com.imooc.girl.controller.GirlController.*(..))")
public void log(){
System.out.println("exec GirlController.* before");
}
@After("execution(public * com.imooc.girl.controller.GirlController.*(..))")
public void logAfter(){
System.out.println("exec GirlController.* after");
}
}
3、提取注解@Before与@After的切点使用@Pointcut。
@Aspect
@Component
public class HttpAspect {
@Pointcut("execution(public * com.imooc.girl.controller.GirlController.*(..))")
public void log(){
}
@Before("log()")
public void doBefore(){
System.out.println("exec GirlController.* before");
}
@After("log()")
public void doAfter(){
System.out.println("exec GirlController.* after");
}
}
4、使用Spring自带的org.slf4j.Logger代替System.out.println打印日志。
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
@Pointcut("execution(public * com.imooc.girl.controller.GirlController.*(..))")
public void log(){
}
@Before("log()")
public void doBefore(){
logger.info("exec GirlController.* before");
}
@After("log()")
public void doAfter(){
logger.info("exec GirlController.* after");
}
}
2018-09-06 11:05:21.345 INFO 8752 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : exec GirlController.* before
Hibernate: select girl0_.id as id1_0_0_, girl0_.age as age2_0_0_, girl0_.cup_size as cup_size3_0_0_ from girl girl0_ where girl0_.id=?
2018-09-06 11:05:21.439 INFO 8752 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : exec GirlController.* after
5、获取请求的相关信息。
@Before("log()")
public void doBefore(JoinPoint joinPoint){
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//1 URL
logger.info("url={}",request.getRequestURL());
//2 method
logger.info("method={}",request.getMethod());
//3 ip
logger.info("ip={}",request.getRemoteAddr());
//4 类方法
logger.info("class_method={}",joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
//5 参数
logger.info("args={}",joinPoint.getArgs());
}
2018-09-06 11:16:54.471 INFO 6908 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : url=http://127.0.0.1:8182/girl/girls/5
2018-09-06 11:16:54.472 INFO 6908 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : method=GET
2018-09-06 11:16:54.472 INFO 6908 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : ip=127.0.0.1
2018-09-06 11:16:54.476 INFO 6908 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : class_method=com.imooc.girl.controller.GirlController.girlFindOne
2018-09-06 11:16:54.476 INFO 6908 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : args=5
Hibernate: select girl0_.id as id1_0_0_, girl0_.age as age2_0_0_, girl0_.cup_size as cup_size3_0_0_ from girl girl0_ where girl0_.id=?
2018-09-06 11:16:54.566 INFO 6908 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : exec GirlController.* after
6、获取返回值相关信息
@AfterReturning(returning = "object",pointcut = "log()")
public void doAfterReturning(Object object){
logger.info("response={}",object);
}
Hibernate: select girl0_.id as id1_0_0_, girl0_.age as age2_0_0_, girl0_.cup_size as cup_size3_0_0_ from girl girl0_ where girl0_.id=?
2018-09-06 11:21:46.138 INFO 8408 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : exec GirlController.* after
2018-09-06 11:21:46.139 INFO 8408 --- [nio-8182-exec-1] com.imooc.girl.aspect.HttpAspect : response=Optional[Girl{id=5, cupSize='B', age=19}]
统一异常处理
1、统一返回对象的实体类。
public class Result<T> {
/* 错误码 */
private Integer code;
/*提示信息*/
private String msg;
/* 返回的具体内容*/
private T data;
public Result() {
}
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 +
'}';
}
}
2、修改Controller中的返回结果。
/**
* 添加一个女生
* @return
*/
@PostMapping(value = "/girls")
public Result<Girl> girlAdd(@Valid Girl girl, BindingResult bindingResult){
Result<Girl> result = new Result<>();
if(bindingResult.hasErrors()){
result.setCode(1);
result.setMsg(bindingResult.getFieldError().getDefaultMessage());
return result;
}
Girl insertData = this.girRepository.save(girl);
result.setCode(0);
result.setMsg("成功");
result.setData(insertData);
return result;
}
3、写一个工具类,提取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;
}
}
4、获取某女生的年龄并判断
<10,返回“应该在上小学”
10<age<16,返回“可能在上初中”
编写GirlController.java
@GetMapping(value = "girls/getAge/{id}")
public void getAge(@PathVariable("id")Integer id) throws Exception {
this.girlService.getAge(id);
}
编写GirlService.java
public void getAge(Integer id) throws Exception {
Optional<Girl> girl = this.girRepository.findById(id);
Integer age = girl.get().getAge();
if(age<10){
throw new GirlException(100,"你还在上小学吧");
}else if(age>10&&age<16){
throw new GirlException(101,"你可能在上初中");
}
}
编写GirlException.java,可以传Code。
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;
}
}
编写拦截Exception的ExceptionHandle.java
@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());
}
logger.error("[系统异常]{}",e);
return ResultUtil.error(-1,"未知错误:"+e.getMessage());
}
}
5、使用枚举,管理异常代码
public enum ResultEnum {
UNKNOW_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 void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
修改对应的GirlException构造器及抛异常代码。
GirlService.java
public void getAge(Integer id) throws Exception {
Optional<Girl> girl = this.girRepository.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);
}
}
单元测试
测试Service
测试API
测试Service
1、在test中编写代码,选中方法名,右击并选中进行测试。
@RunWith(SpringRunner.class)
@SpringBootTest
public class GirlServiceTest {
@Autowired
private GirlService girlService;
@Test
public void findOneTest(){
Girl girl = girlService.findOne(4);
Assert.assertEquals(new Integer(14),girl.getAge());
}
}
2、利用Idea,创建测试的java代码
3、对controller进行测试
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class GirlControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void girlList() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/girls"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("llllll"));
}
}
5、maven打包:mvn clean package
maven打包跳过单元测试:mvn clean package -Dmaven.test.skip=true;