0%

SpringBoot学习笔记

启动方式

  1. IDE启动
  2. mvn spring-boot:run
  3. mvn install 编译微jar包后,运行java -jar 项目的jar名

属性配置

Spring Boot 不单单从 application.properties 获取配置,所以我们可以在程序中多种设置配置属性。按照以下列表的优先级排列:

  1. 命令行参数
  2. java:comp/env 里的 JNDI 属性
  3. JVM 系统属性
  4. 操作系统环境变量
  5. RandomValuePropertySource 属性类生成的 random.* 属性
  6. 应用以外的 application.properties(或 yml)文件
  7. 打包在应用内的 application.properties(或 yml)文件
  8. 在应用 @Configuration 配置类中,用 @PropertySource 注解声明的属性文件
  9. SpringApplication.setDefaultProperties 声明的默认属性在.properties或.yml配置文件中配置。

yml配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 普通变量:使用时定义了变量后使用@Value(“${name}”)注解即可。
name: 刘备
age: 55

# 与JavaBean关联
# 在Person.class中,使用注解:
# @Component
# @ConfigurationProperties(prefix = "person")
# 使用时通过@Autowired注解:
# @Autowired
# private Person person;
# 通过不同的启动方式使用不同的配置
person:
name: 刘备
age: 55

# 在application-dev.yml和application-prod.yml配置文件中保存不同的变量值,在application.yml中通过以下方式使用:
spring:
profiles:
active: dev

资源映射

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/image/**") //请求的url
.addResourceLocations("file:///" + Utils.getResPath()); //文件本地目录
super.addResourceHandlers(registry);
}
}

Controller

  • @Controller:处理http请求
  • @RestController:@ResponseBody+@Controller
  • @RequestMapping:配置url映射
  • @PathVariable:获取url中参数
  • @RequestParam:获取请求参数的值
  • @GetMapping
  • @PostMapping
  • @PutMapping
  • @DeleteMapping

注意:

  1. @RequestMapping(“/hello/{id})
    …(@PathVariable(“id”) Integer id)
    ——》这种方式的url直接在反斜杠后加参数即可访问
  2. 而如果使用传统URL(…/..?id=..),则需要使用@RequestParam注解。
  3. GetMapping= RequestMapping+GET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 返回Json
@RestController
public class TestController {

@Value("${name}")
private String name;

@Autowired
private Person person;

@GetMapping("/hello/{id}")
public Person hello(@PathVariable("id") String hello) {
return person;
}
}

表单验证

对某个字段添加限制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Min(value = 18, message = "未成年")
private Integer age;

@PostMapping("/user")
public User addUser(@Valid User u, BindingResult result){
if (result.hasErrors()){
System.out.println(result.getFieldError().getDefaultMessage());
return null;
}
User user = new User();
user.setAge(u.getAge());
user.setName(u.getName());
return userRepository.save(user);
}

DI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class DI() {
//通过构造器注入
private DependencyA a;
@Autowired
public DI(DependencyA a) {
this.a = a;
}

//通过setter方法注入
private DependencyB b;
@Autowired
public void setDependencyB (DependencyB b){
this.b = b;
}

//通过field反射注入
@Autowired
private DependencyC c;
}
  • 构造器注入:当有十几个甚至更多对象需要注入时,你的构造函数的参数个数可能会长到无法想像。
  • field反射注入:如果不使用Spring框架,这个属性只能通过反射注入,根本不符合JavaBean规范。还有,当不是用Spring创建的对象时,还可能引起NullPointerException。并且,不能用final修饰这个属性。
  • setter方法注入:不能将属性设置为final。
  • 如果注入的属性是必选的属性,则通过构造器注入。
  • 如果注入的属性是可选的属性,则通过setter方法注入。
  • 至于field注入,不建议使用。

AOP

是一种编程思想,不是语言特有的。

  • 使用@Aspect注解将一个java类定义为切面类
  • 使用@Pointcut定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等。
  • 根据需要在切入点不同位置的切入内容
    • 使用@Before在切入点开始处切入内容
    • 使用@After在切入点结尾处切入内容
    • 使用@AfterReturning在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
    • 使用@Around在切入点前后切入内容,并自己控制何时执行切入点自身的内容
    • 使用@AfterThrowing用来处理当切入内容部分抛出异常之后的处理逻辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@org.aspectj.lang.annotation.Aspect
@Component
public class Aspect {

@Pointcut("execution(public * com.hearing.springdemo.controller.*.*(..))")
public void log(){
}

@Before("log()")
public void doBefore(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println(Arrays.toString(args));
System.out.println("doBefore...");
}

@AfterReturning(returning = "object", pointcut = "log()")
public void doAfter(Object object){
System.out.println("doAfter...");
}
}

Listener

执行顺序:监听器、过滤器、拦截器。

分类

  • 监听域对象自身的创建和销毁的事件监听器
    ServletContextListener,HttpSessionListener,ServletRequestListener。
  • 监听域对象中属性的增加和删除的事件监听器
    ServletContextAttributeListener,HttpSessionAttributeListener,ServletRequestAttributeListener。
  • 监听绑定到HttpSession域中的某个对象的状态的事件监听器
    HttpSessionBindingListener:对象的绑定与解绑(将要绑定对象实现该接口)
    HttpSessionActivationListener:对象的钝化与活化(将要绑定对象实现该接口)
  • Session钝化机制:将服务器中不经常使用的Session对象暂时序列化到文件系统或数据库系统中,当被使用时反序列化到内存。

使用

@WebListener方式

主类添加@ServletComponentScan注解

1
2
3
4
5
6
7
8
9
10
11
12
13
@WebListener
public class MyServletContextListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println(sce.getServletContext().getServletContextName()+" init");
}

@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println(sce.getServletContext().getServletContextName()+" destroy");
}
}

ServletListenerRegistrationBean代码注册

1
2
3
4
5
6
7
8
9
10
@Configuration
public class ListenerConfigure {

@Bean
public ServletListenerRegistrationBean<MyHttpSessionListener> serssionListenerBean(){
ServletListenerRegistrationBean<MyHttpSessionListener>
sessionListener = new ServletListenerRegistrationBean<MyHttpSessionListener>(new MyHttpSessionListener());
return sessionListener;
}
}

Filter

概述

与Servlet相似,过滤器是一些web应用程序组件,可以绑定到一个web应用程序中。但是与其他web应用程序组件不同的是,过滤器是”链”在容器的处理过程中的。这就意味着它们会在servlet处理器之前访问一个进入的请求,并且在外发响应信息返回到客户前访问这些响应信息。这种访问使得过滤器可以检查并修改请求和响应的内容。

chain.doFilter将请求转发给过滤器链下一个filter , 如果没有filter那就是你请求的资源。可通过配置CharacterEncodingFilter来解决请求乱码的问题。

步骤

  1. 实现Filter【javax.servlet.Filter】接口,实现Filter方法。
  2. 添加 @Configuration 注解,将自定义Filter加入过滤链;或Filter中添加@WebFilter注解,主类添加@ServletComponentScan注解
1
2
3
4
5
6
7
8
9
10
11
@Bean
public FilterRegistrationBean testFilterRegistration() {

FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new TestFilter());
registration.addUrlPatterns("/*");
registration.addInitParameter("paramName", "paramValue");
registration.setName("testFilter");
registration.setOrder(1);
return registration;
}

或:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Order(1)
@WebFilter(filterName = "testFilter1", urlPatterns = "/*")
public class TestFilterFirst implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
System.out.println("TestFilter1");
filterChain.doFilter(servletRequest,servletResponse);
}

@Override
public void destroy() {

}
}

拦截器

概述

SpringBoot的拦截器只能拦截流经DispatcherServlet的请求,对于自定义的Servlet无法进行拦截。

SpringMVC中的拦截器有两种:HandlerInterceptor和WebMvcInterceptor。

拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

  1. 日志记录:记录请求信息的日志,以便进行信息监控、信息统计等。
  2. 权限检查:如登录检测,如果没有直接返回到登录页面;
  3. 性能监控:可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
  4. 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息,解决请求乱码等,只要是多个处理器都需要的即可使用拦截器实现。
  5. OpenSessionInView:如hibernate,在进入处理器打开Session,在完成后关闭Session。

拦截器是AOP的一种实现,底层通过动态代理模式完成。区别:

  • 拦截器是基于Java的反射机制的,而过滤器是基于函数回调。
  • 拦截器不依赖于servlet容器,而过滤器依赖于servlet容器。
  • 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
  • 拦截器可以访问action上下文、值栈里的对象,而过滤器不能。
  • 在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/** 
*
* 注册拦截器
*/
public class WebAppConfig extends WebMvcConfigurerAdapter {

@Override
public void addInterceptors(InterceptorRegistry registry) {
//注册自定义拦截器,添加拦截路径和排除拦截路径
registry.addInterceptor(new InterceptorConfig()).addPathPatterns("api/path/**").excludePathPatterns("api/path/login");
}
}

public class InterceptorConfig implements HandlerInterceptor{

private static final Logger log = LoggerFactory.getLogger(InterceptorConfig.class);

/**
* 进入controller层之前拦截请求
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {

log.info("---------------------开始进入请求地址拦截----------------------------");
HttpSession session = httpServletRequest.getSession();
if(!StringUtils.isEmpty(session.getAttribute("userName"))){
return true;
}
else{
PrintWriter printWriter = httpServletResponse.getWriter();
printWriter.write("{code:0,message:\"session is invalid,please login again!\"}");
return false;
}

}

@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
log.info("--------------处理请求完成后视图渲染之前的处理操作---------------");
}

@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
log.info("---------------视图渲染之后的操作-------------------------0");
}
}

执行顺序

跨域

概述

同源策略[same origin policy]是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源。 同源策略是浏览器安全的基石。

源[origin]就是协议、域名和端口号。若地址里面的协议、域名和端口号均相同则属于同源。

哪些操作不受同源策略限制:

  • 页面中的链接,重定向以及表单提交是不会受到同源策略限制的;
  • 跨域资源的引入是可以的。但是JS不能读写加载的内容。如嵌入到页面中的