系统架构
什么是Spring IO Platform
Spring IO Platform,简单的可以认为是一个依赖维护平台,该平台将相关依赖汇聚到一起,针对每个依赖,都提供了一个版本号;
这些版本对应的依赖都是经过测试的,可以保证一起正常使用。
为什么要使用Spring IO Platform
主要是解决依赖版本冲突问题,例如在使用Spring的时候,经常会使用到第三方库,一般大家都是根据经验挑选一个版本号或挑选最新的,随意性较大,其实这是有问题的,除非做过完整的测试,保证集成该版本的依赖不会出现问题,且后续集成其它第三方库的时候也不会出现问题,否则风险较大,且后续扩展会越来越困难,因为随着业务复杂度的增加,集成的第三方组件会越来会多,依赖之间的关联也会也来越复杂。
好消息是,Spring IO Platform能很好地解决这些问题,我们在添加第三方依赖的时候,不需要写版本号,它能够自动帮我们挑选一个最优的版本,保证最大限度的扩展,而且该版本的依赖是经过测试的,可以完美的与其它组件结合使用。
Spring IO Platform pom
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.imooc.security</groupId>
<artifactId>imooc-security</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<imooc.security.version>1.0.0-SNAPSHOT</imooc.security.version>
</properties>
#有这两个依赖就可以将项目的依赖管理起来了start
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>Brussels-SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
#有这两个依赖就可以将项目的依赖管理起来了end
#配置maven的编译信息start
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
#配置maven的编译信息end
<modules>
<module>../imooc-security-app</module>
<module>../imooc-security-browser</module>
<module>../imooc-security-core</module>
<module>../imooc-security-demo</module>
<module>../imooc-security-authorize</module>
</modules>
</project>
一个模块引入另外一个模块的依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>imooc-security-app</artifactId>
<parent>
<groupId>com.imooc.security</groupId>
<artifactId>imooc-security</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../imooc-security</relativePath>
</parent>
#这边引入了com.imooc.security模块的全部依赖,需在父类中加入版本说明
<dependencies>
<dependency>
<groupId>com.imooc.security</groupId>
<artifactId>imooc-security-core</artifactId>
<version>${imooc.security.version}</version>
</dependency>
</dependencies>
</project>
打包一个可执行web服务的jar包?加一个编译插件
在打包成web服务模块的.pom文件中加入插件
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.6.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<finalName>demo</finalName>
</build>
restful Api与常规的Api的区别
1.常规的使用json来定义请求的成功或者失败
2.restful Api使用http的状态码来确定请求的成功或者失败
restful Api的描述
Spring的测试框架、测试用例的使用
1.模块中加入pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.5.6.RELEASE</version>
</dependency>
2.在模块中添加测试用例
package com.imooc.web.controller;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@RunWith(SpringRunner.class) //表示如何来运行这个测试用例,我们用SpringRunner来运行
@SpringBootTest //表示这个类是一个springBoot的测试用例
public class UserControllerTest {
//因为我们要测的是一个web程序,所以我们要伪造一个Mvc的环境,伪造的
// 环境不会真正的启动我们的tomcat,所以测试用例执行的时候会很快
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;//伪造mvc的环境
@Before //会在测试用例执行之前执行
public void setup(){
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();//伪造一个mvc环境
}
//开始写一个测试用例
@Test
public void whenQuerySuccess() throws Exception {
String result = mockMvc.perform(get("/user").param("username", "jojo").param("age", "18").param("ageTo", "60").param("xxx", "yyy")
// .param("size", "15")
// .param("page", "3")
// .param("sort", "age,desc")
.contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(status().isOk()).andExpect(jsonPath("$.length()").value(3))
.andReturn().getResponse().getContentAsString();
System.out.println(result);
}
}
idea导入eclipse的maven项目
idea运行单个测试用例及运行所有测试用例的方法
1.双击单个方法,run as
2.在文件上 run as
Spring的一些用法
1.@PathVariable将路径上的参数作为方法参数导入
2.@GetMapping("/{id:\d+}") ///使用正则表达式表示接受数字类型的参数
@JsonView的使用
1-2
3.在controller中指定视图
********************** 1.RESTful Api *****************************
1.RequestBody映射请求体到javaj方法的参数///
2.日期类型参数的处理
///通过传递时间戳到前端,让前台来决定展示格式
3.valid注解和BindingResult验证请求参数的合法性并处理验证结果
1)添加@valid的
2)添加需要验证的字段
3)BindingResult让验证可以进入函数体
///比如在校验参数没过时,需要记录日志
************************************************************
4)常用的验证注解
获取错误的字段和信息
5)自定义验证消息
6)自定义验证注解
1.自定义验证注解
2.验证逻辑
3.调用验证器
RESTful Api错误处理机制
1)Spring Boot 中默认的错误处理机制
2)如何自定义异常处理
定义浏览器的错误请求页面
自定义运行时异常
1)异常类处理
package com.imooc.exception;
public class UserNotExistException extends RuntimeException {
private static final long serialVersionUID = -6112780192479692859L;
private String id;
public UserNotExistException(String id) {
super("user not exist");
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
2)调用抛出异常
throw new UserNotExistException (String id);
3)添加自己的异常信息(将id信息返回到异常信息)
package com.imooc.web.controller;
import com.imooc.exception.UserNotExistException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice //代表这个类的方法都是处理其他Controller控制器所抛出的异常的 =>不处理请求,值处理controller请求
public class ControllerExceptionHandler {
@ExceptionHandler(UserNotExistException.class) //任何一个方法抛出一个UserNotExistException异常是,都会执行下面的方法
@ResponseBody //返回json
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public Map<String, Object> handleUserNotExistException(UserNotExistException ex) { //拿到抛出的异常
Map<String, Object> result = new HashMap<>();
result.put("id", ex.getId());
result.put("message", ex.getMessage());
return result;
}
}
RESTful Api拦截器
1)过滤器
/**
*
*/
package com.imooc.web.filter;
import java.io.IOException;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @author zhailiang
*
*/
//@Component //要让过滤器起作用,申明成一个spring的Component,所有的流程都会经过这个过滤器
public class TimeFilter implements Filter {
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy() {
//销毁
System.out.println("time filter destroy");
}
/* (non-Javadoc)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//执行
System.out.println("time filter start");
long start = new Date().getTime();
chain.doFilter(request, response);
System.out.println("time filter 耗时:"+ (new Date().getTime() - start));
System.out.println("time filter finish");
}
/* (non-Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig arg0) throws ServletException {
//初始化
System.out.println("time filter init");
}
}
如何把一个普通(第三方的过滤器)类加到项目过滤器链中
/**
*
*/
package com.imooc.web.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.imooc.web.filter.TimeFilter;
import com.imooc.web.interceptor.TimeInterceptor;
/**
* @author zhailiang
*
*/
@Configuration //**告诉spring这个类是一个配置类
public class WebConfig extends WebMvcConfigurerAdapter {
@SuppressWarnings("unused")
@Autowired
private TimeInterceptor timeInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(timeInterceptor);
}
// @Bean //**注册一个FilterRegistrationBean的bean
public FilterRegistrationBean timeFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
TimeFilter timeFilter = new TimeFilter();
registrationBean.setFilter(timeFilter);//**设置过滤器
List<String> urls = new ArrayList<>();
urls.add("/*");//**配置过滤器的URL
registrationBean.setUrlPatterns(urls);
return registrationBean;
}
}
2)拦截器
//过滤器不知道请求的处理函数?
1.申明拦截器
/**
*
*/
package com.imooc.web.interceptor;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* @author zhailiang
*
*/
@Component
public class TimeInterceptor implements HandlerInterceptor {
/* (non-Javadoc)
* @see org.springframework.web.servlet.HandlerInterceptor#preHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle");
System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
System.out.println(((HandlerMethod)handler).getMethod().getName());
request.setAttribute("startTime", new Date().getTime());
return true;
}
/* (non-Javadoc)
* @see org.springframework.web.servlet.HandlerInterceptor#postHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.web.servlet.ModelAndView)
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
Long start = (Long) request.getAttribute("startTime");
System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));
}
/* (non-Javadoc)
* @see org.springframework.web.servlet.HandlerInterceptor#afterCompletion(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion");
Long start = (Long) request.getAttribute("startTime");
System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));
System.out.println("ex is "+ex);
}
}
2.注册拦截器
3)切片