SpringBoot详解

嘿嘿,我的SpringBoot入门教程。随便写写。

项目链接

pom.xml文件

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
一个简单的项目所使用的这个依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
很多童鞋会好奇 为什么只要一个依赖就可以运行项目

其实这里启用的maven的依赖继承的概念。
我们不妨点进去看下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
</dependencies>

哦, 原来是这样。

org/
springframework/
boot/spring-boot-starter-web/
1.5.10.RELEASE/
spring-boot-starter-web-1.5.10.RELEASE.pom文件中原来还依赖这么多。

我们先看下面几个依赖
1. spring-boot-starter-tomcat
这就是我们为什么不用再在项目中添加web容器依赖的原因。(springboot在这里已经帮我们依赖好了)

2. hibernate-validator
这里就是我们为什么可以在项目的entity类中可以使用@Null @Max注解进行校验的的原因。(springboot帮我们集成了hibernate的验证的jar)

3. jackson-databind 这里是jackson家族的数据绑定的依赖。(也默认帮我们集成了)

4. spring-web spring-webmvc 这里就是为什么可以处理http请求的原因(相当于使用的springMVC)

最后在看上面的一个spring-boot-starter, springboot在这里居然还有上一层依赖。
我们不妨点进去再看一下
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
start里面还集成了好多的东西:如日志以及一些autoconfig的东西

其实到这里我们我们还可以对spring-boot再点进去看下
其实该依赖中才是真正集成spring的地方:(core,context ...)
太多了, 我就贴一点出来
<dependencies>
<!-- Compile -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- Optional -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jms</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<optional>true</optional>
</dependency>


到这里我们应该知道了, 为什么我们写springboot的应用的时候,会如此简单。
springboot还帮我们搞了一套starter组件
我们可以不用管理框架版本的问题
这个依赖也很重要,继承父依赖,统一管理
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

starter组件如:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!--项目在部署的时候, 打开注释, exclude掉springBoot自带的tomcat-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>

原来springboot帮我们预处理了这么多事情:默认的依赖、默认的配置等。
这也是的我们得心应手的原因。
话不多说: 赶紧动手吧!

默认配置文件 application.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
随便写两个配置
server.context-path=/bott
server.port=8989
指定项目的上下文和端口号

当然了, 我们一般不用默认的配置文件的格式, 我们改用yml格式

yml格式的优点:
1. 便于管理配置(列表式方式)
2. yml格式比默认的properties格式 更加不容易乱码(yml 格式中一些中文属性的取值不会出现乱码)

看下yml格式(注意冒号后面有一个空格哦) 还有上下文前面一定要加上‘/’路径分隔符,否则会报错。
server:
context-path: /bott
port: 8989

默认的Resouces目录

存放着 一些项目的配置文件application.properties、静态文件夹static, 模板文件夹templates

1
2
3
4
5
6
7
8
9
可能有童鞋很好奇这些文件夹都是springboot在哪儿默认配置的?

双击Shift 全局搜索ResourceProperties.class文件
对! springboot的默认配置(autoconfig)就是在这个类中配置的
# org/springframework/boot/autoconfigure/web/ResourceProperties.class

在这里指定了路径文件夹
private static final String[] SERVLET_RESOURCE_LOCATIONS = new String[]{"/"};
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};

默认的启动类SpringApplication.class

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
该类中主要的注解
@SpringBootApplication
该注解很重要哦,是一个组合注解
springboot启动时 一些默认配置autoconfiguration以及componentScan等都是依靠该注解

我们可以点进去看看

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
上面都是一个java中注解中的元注解

@SpringBootConfiguration
@EnableAutoConfiguration
上面两个注解开启了springboot的默认自动配置, 这也是我们为什么不用写那么多xml配置文件原因
也体现了 springboot 中 ‘约定大于配置’ 的理念。

下面的注解实现自动扫描包和最重要的包中所使用的注解,
这样才能通过注解的方式是程序正常工作
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {...}


还有一点要注意的事:
我们项目写的文件必须要放在启动类SpringApplication.class文件所在的包中或者子包中都行,
这样componentScan才能扫描到。

helloworld

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
定义一个controller
package com.dottie.boot.Controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController # 组合注解 @Controller @ResponseBody
public class HelloController {

@GetMapping(value = "/hello") # 定义接受一个Get请求, 并制定请求的url
public String hello() {
return "hello world";
}
}

启动方式有很多,
这里我们先直接在springApplication类中点击左边的启动三角符号。
然后在浏览器中输入context 和 port 以及路径 hello 就可访问。

当然了, 也可以在命令行中启动
1. 进到项目文件夹中,用maven将项目打包
daejong@dottie ~/Documents/Java/java_workSpace/boot
mvn clean package
[INFO] --- spring-boot-maven-plugin:1.5.10.RELEASE:repackage (default) @ boot ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.408 s
[INFO] Finished at: 2018-02-23T16:54:45+08:00
[INFO] Final Memory: 30M/277M
[INFO] ------------------------------------------------------------------------
打包成功

2. daejong@dottie ~/Documents/Java/java_workSpace/boot
java -jar target/boot-0.0.1-SNAPSHOT.jar

最后输入以下信息, 启动成功
。。。
2018-02-23 16:56:42.275 INFO 30516 --- [nio-8989-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2018-02-23 16:56:42.293 INFO 30516 --- [nio-8989-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 18 ms

模板的访问

这里使用的模板引擎是 freemarker 当然了也可以使用其他的
springboot默认的是thymeleaf模板引擎

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
1. 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>

2. 在application.yml中配置
spring:
freemarker:
#关闭缓存
cache: false
request-context-attribute: request
#模板加载的位置
template-loader-path: classpath:/templates # 这是默认配置
#后缀
prefix: / # 默认配置
#前缀
suffix: .html # 这里默认是ftl 我们修改为html

3. 定义controller
package com.dottie.boot.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class WorldController {

@GetMapping(value = "index")
public String index() {
return "index"; # 指定模板的名称
}
}

4. 浏览器正常访问项目

最后还有就是springMVC中的知识了
如:传值给模板 定义ModelAndView等等。

全局异常的捕获

项目如果没有对异常处理的话, 服务器就会宕机。这是万万不允许的。

所以 需要一个全局异常的捕获。才能保证项目的正常运行。

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
如: 我们进行 1/0 操作, 服务器就会挂了。
@GetMapping(value = "test")
public void test() {
int a = 1/0;
}
然后访问进行访问
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Fri Feb 23 17:28:26 CST 2018
There was an unexpected error (type=Internal Server Error, status=500).
/ by zero 服务器发现除零异常, 然后就宕机了。

但是,我们用一个全局异常定义下就可以进行使得服务器正常运行。

1. 定义一个全局异常的Controller
package com.dottie.boot.Controller;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class GlobalException {

/**
* 全局处理所有异常
*/
@ExceptionHandler(Exception.class)
@ResponseBody
public Map<String, Object> allErrorHandler(Exception ex) {
Map<String, Object> map = new HashMap<>();
map.put("code", -1);
map.put("msg", ex.getMessage());
return map;
}

}

我们再次进行访问
返回了我们自定义的异常结果
{"msg":"/ by zero","code":-1}
最重要的是服务器不会宕机。


当然了, 我们也可以自定义一些特定的异常。
如AppException.class

package com.dottie.boot.Exception;
import lombok.Data;
@Data
public class AppException extends RuntimeException{
private Integer code;

private String message;

public AppException(String message, Integer code) {
this.code = code;
this.message = message;
}
}

/**
* 项目自定义异常
*/
@ExceptionHandler(AppException.class)
@ResponseBody
public Map<String, Object> errorHandler(AppException ex) {
Map<String, Object> map = new HashMap<>();
map.put("code", ex.getCode());
map.put("msg", ex.getMessage());
return map;
}


@GetMapping(value = "testEx1")
public void test1() {
throw new AppException("我是自定义异常,被全局捕获了", 110);
}

浏览器访问后返回的结果:
{"msg":"我是自定义异常,被全局捕获了","code":110}

集成JPA

个人看法: JPA主张NoSql 确实方便。 但是初学者 会有很多坑。

必须确保所有的命名都正确。程序才能运行。(我刚用JPA时, 也踩了好多坑)

反正我是不喜欢用 JPA, 我还是喜欢Mybatis这种半自动化的框架(自己定制sql语句)

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
1. 添加数据库和jpa的依赖
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>

<!--jpa操作数据库-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

2. 配置jpa和数据源
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://localhost:3306/dbman?characterEncoding=utf-8&useSSL=false

jpa:
show-sql: true
hibernate:
ddl-auto: update # 自动建表

3. 定义数据库实体类dataObject
package com.dottie.boot.Entity;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
@Data
public class ManEntity {

@Id
private String id;

private String name;

private Double salary;
}

这个时候,我们运行下项目。 就会帮我们自动在数据库中新建的一张表
注意命名(根据我们定义的实体类来命名):man_entity
mysql> desc man_entity;
+--------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| id | varchar(255) | NO | PRI | NULL | |
| name | varchar(255) | YES | | NULL | |
| salary | double | YES | | NULL | |
+--------+--------------+------+-----+---------+-------+
3 rows in set (0.01 sec)

4. 不过如果数据库早就存在。 我们只要定义和数据表相同的字段属性即可。
但是要注意的是 数据表的名称是如何定义的
比如:实体类是ManEntity --> 数据表就是man_entity
实在不行可以修改下数据表的名称

我目前的数据表数据如下:
mysql> select * from girl_entity;
+----+------+----------+
| id | age | cup_size |
+----+------+----------+
| 1 | 99 | D |
| 3 | 101 | D |
| 4 | 102 | D |
| 5 | 26 | E |
| 6 | 26 | E |
| 7 | 1111 | G |
| 8 | 1112 | F |
| 11 | 18 | F |
| 12 | 18 | F |
| 13 | 14 | F |
| 14 | 7 | E |
| 15 | 28 | G |
| 16 | 222 | G |
+----+------+----------+

所以我要定义与之对应的实体类
package com.dottie.boot.Entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity //必须要添加的注解, 根据该注解 实现实体类和数据表的对应。
@Data
public class GirlEntity {

@Id
private String id; // 每张表必须指定一个主键 @Id 否则程序崩掉。
private String age;
private String cupSize; //注意驼峰命名法(数据表中就是 cup_size)
}

5. 定义Repository
package com.dottie.boot.Repository;

import com.dottie.boot.Entity.GirlEntity;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface ManRepository extends JpaRepository<GirlEntity, String> {

List<GirlEntity> findGirlEntityByCupSize(String cupSize);
}

注意这里我们使用的是接口
这里我们指定JpaRepository<GirlEntity, String>
然后可以输入findBy然后根据IDEA的智能提示*****
findGirlEntityByCupSize补全即可
话说JPA确实强大。 甚至还可以ByCupSizeAndAge等等。

6. 定义Service
package com.dottie.boot.Service.impl;

import com.dottie.boot.Entity.GirlEntity;
import com.dottie.boot.Repository.ManRepository;
import com.dottie.boot.Service.ManService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ManServiceImpl implements ManService {

@Autowired
private ManRepository manRepository;

@Override
public List<GirlEntity> findByCupsize(String cupsize) {
return manRepository.findGirlEntityByCupSize(cupsize);
}
}

7. 定义Controller
package com.dottie.boot.Controller;

import com.dottie.boot.Entity.GirlEntity;
import com.dottie.boot.Service.ManService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class ManController {

@Autowired
private ManService manService;

@GetMapping(value = "girls/{size}")
public List<GirlEntity> getGirls(@PathVariable("size") String size) {
return manService.findByCupsize(size);
}
}

8. 浏览器请求数据
localhost:8989/bott/girls/D
返回数据如下:
[
{"id":"1","age":"99","cupSize":"D"},
{"id":"3","age":"101","cupSize":"D"},
{"id":"4","age":"102","cupSize":"D"}
]

过滤器的使用

方式一 注解式

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
package com.dottie.boot.Filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
* 使用注解的方式来使用过滤器
* 注意这种方式要在启动类中加上 @ServletComponentScan
*
*
* 这里直接用@WebFilter就可以进行配置,同样,可以设置url匹配模式,过滤器名称等。
* 这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。
* 除了这个注解以外,我们还需在配置类中加另外一个注解:@ServletComponetScan,指定扫描的包。
*/
@WebFilter(filterName = "AnnoFilter", urlPatterns = {"/hello", "/index"})
public class AnnoFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("注解方式使用过滤器。。。");
}

@Override
public void destroy() {

}
}

方式二:@Configuration手动配置(推荐使用)

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
52
53
54
55
56
57
58
59
60
61
62
1. 先写一个过滤器Filter
package com.dottie.boot.Filter;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* 测试 filter
* 请求操作耗时例子
* 过滤器,主要的用途是过滤字符编码、做一些业务逻辑判断等。
*/
@Slf4j
public class LogCostFitler implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
long start = System.currentTimeMillis();
filterChain.doFilter(httpServletRequest, httpServletResponse);
log.info("操作耗时: " + (System.currentTimeMillis() - start) + " 毫秒");
}

@Override
public void destroy() {

}
}


2. 新建一个配置类
package com.dottie.boot.Configuration;

import com.dottie.boot.Filter.LogCostFitler;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
LogCostFitler logCostFitler = new LogCostFitler();
filterRegistrationBean.setFilter(logCostFitler);
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setName("LogCostFilter");
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
}

即可

拦截器的使用

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
1. 新建一个拦截器
package com.dottie.boot.Interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* 拦截器,在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。是基于JAVA的反射机制
*/
public class LogCostInterceptor implements HandlerInterceptor{

long start = System.currentTimeMillis();

/**
* //在请求处理之前进行调用(Controller方法调用之前)
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
start = System.currentTimeMillis();
System.out.println("Interceptor Begin...");
// return false 则进行拦截,停止请求
return true;
}

/**
* //请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor cost="+(System.currentTimeMillis()-start));
}

/**
* //在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
* @param httpServletRequest
* @param httpServletResponse
* @param o
* @param e
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("afterCompletion被调用");
}
}

2. 再建一个配置类对拦截器注册
package com.dottie.boot.Configuration;

import com.dottie.boot.Interceptor.LogCostInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
LogCostInterceptor logCostInterceptor = new LogCostInterceptor();
registry.addInterceptor(logCostInterceptor).addPathPatterns("/*");
super.addInterceptors(registry);
}
}

监听器的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.dottie.boot.Listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

/**
* 监听器,做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等
*/
@WebListener
public class FirstListener implements ServletContextListener{
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("listener 初始化。。。");
}

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("listener 销毁");
}
}

区别和用途

1
2
3
4
5
6
7
8
9
10
11
12
13
14
区别:
拦截器是基于java的反射机制的,而过滤器是基于函数回调
过滤器依赖与servlet容器,而拦截器不依赖与servlet容器
拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用
拦截器可以访问action上下文、值栈里的对象,而过滤器不能
action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次


用途:
过滤器,主要的用途是过滤字符编码、做一些业务逻辑判断等。

监听器,做一些初始化的内容添加工作、设置一些基本的内容、比如一些参数或者是一些固定的对象等等

拦截器,在面向切面编程中应用的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。是基于JAVA的反射机制

生成jar后台运行

  1. java -jar app.jar(一般测试用这种方式) 缺点当前ssh窗口被锁定,可按CTRL + C打断程序运行,或直接关闭窗口,此时程序也会停止运行。

  2. java -jar app.jar &
    &代表在后台运行。
    特定:当前ssh窗口不被锁定,但是当窗口关闭时,程序中止运行

  3. nohup命令 nohup java -jar app.jar &
    nohup 意思是不挂断运行命令,当账户退出或终端关闭时,程序仍然运行。

  4. nohup java -jar app.jar >output 2>&1 &
    默认输出到nohup.out文件
    jobs命令 查看后台运行任务

  5. 其他部署参考