springBoot(1)--初步理解
在没有用SpringBoot之前,我们用spring和springMVC框架,但是你要做很多比如:
(1)配置web.xml,加载spring和spring mvc
2)配置数据库连接、配置spring事务
3)配置加载配置文件的读取,开启注解
4)配置日志文件
会比较繁琐,但是用springBoot我仅仅只需要非常少的几个配置就可以迅速方便的搭建起来一套web项目或者是构建一个微服务!
小案例
Springboot的Java配置方式是通过 @Configuration 和 @Bean 这两个注解实现的:
1、@Configuration 作用于类上,相当于一个xml配置文件;
2、@Bean 作用于方法上,相当于xml配置中的<bean>;
一.项目project

项目采用的是:maven,eclipse
项目github地址:springbootstudy1
1.pom.xml
<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>cn.binron.springboot</groupId> <artifactId>binron-springboot</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.0.2.RELEASE</version> </dependency> <!-- 连接池 --> <dependency> <groupId>com.jolbox</groupId> <artifactId>bonecp-spring</artifactId> <version>0.8.0.RELEASE</version> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <plugins> <!-- 资源文件拷贝插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- java编译插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> <pluginManagement> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
我在配置pom文件的时候,遇到麻烦就是在本地仓库找不到我的相应jar,从远处仓库下载也下载不到,后来才发现是settings.xml的问题
所以我在网上找了个settings.xml文件,直接把我的给替换掉,然后在 clean --install--update就好了。网上settings.xml文件内容。
2.User对象
public class User {
private String username;
private String password;
private Integer age;
//提供set和get方法
}
3.编写UserDAO 用于模拟与数据库的交互
我把userDao模拟成连接数据库并取得值
public class UserDAO {
public List<User> queryUserList(){
List<User> result = new ArrayList<User>();
// 模拟数据库的查询
for (int i = 0; i < 10; i++) {
User user = new User();
user.setUsername("username_" + i);
user.setPassword("password_" + i);
user.setAge(i + 1);
result.add(user);
}
return result;
}
4.编写UserService 用于实现User数据操作业务逻辑
@Service
public class UserService {
@Autowired // 注入Spring容器中的bean对象
private UserDAO userDAO;
public List<User> queryUserList() {
// 调用userDAO中的方法进行查询
return this.userDAO.queryUserList();
}
}
5. 编写SpringConfig 用于实例化Spring容器
@Configuration //通过该注解来表明该类是一个Spring的配置,相当于一个xml文件
@ComponentScan(basePackages = "cn.itcast.springboot.javaconfig") //配置扫描包
public class SpringConfig {
@Bean // 通过该注解来表明是一个Bean对象,相当于xml中的<bean>
public UserDAO getUserDAO(){
return new UserDAO(); // 直接new对象做演示
}
}
6. 编写测试方法 用于启动Spring容器
public class Main {
public static void main(String[] args) {
// 通过Java配置来实例化Spring容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
// 在Spring容器中获取Bean对象
UserService userService = context.getBean(UserService.class);
// 调用对象中的方法
List<User> list = userService.queryUserList();
for (User user : list) {
System.out.println(user.getUsername() + ", " + user.getPassword() + ", " + user.getPassword());
}
// 销毁该容器
context.destroy();
}
}
最后看后台数据有没有成功打印:

一、快速创建项目
springboot官网提供了工具类自动创建web应用:网址:http://start.spring.io/
官网页面

1、快速创建一个

选择web代表这是一个web项目
这样就可以吧项目放到eclipse或者idea中进行运行了。
这里需要注意几点:
1.springboot2X,所需要mevan是3.0+,JDK是1.8+
2.在做项目开发的时候,主入口Application类(带有注解@SpringBootApplication),要放在所有包之上。
二、初解jackson
jackson是springboot自带的json框架
jackson常用标签
(1)指定字段不返回:@JsonIgnore
(2)指定日期格式:@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss",locale="zh",timezone="GMT+8")
(3)空字段不返回:@JsonInclude(Include.NON_NUll)
(4)指定别名:@JsonProperty
举例:
user对象
public class User {
@JsonProperty("account")
private int age;
@JsonIgnore
private String pwd;
@JsonInclude(Include.NON_NULL)
private String phone;
@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss",locale="zh",timezone="GMT+8")
private Date createTime;
//提供set和get方法,tostring方法
}
Controller类中映射方法
@GetMapping("/testjackson")
public Object testjson(){
return new User(0, "密码", null, new Date());
}
效果演示 接口测试工具是postman


我们发现:
1:日期时间格式变成了指定格式
2:age属性显示在界面变成了:account
3:pwd并没有显示
4:因为phone属性为null,所以也没有显示。
目录结构,文件上传
一、目录结构

1、目录讲解
src/main/java:存放代码
src/main/resources
static: 存放静态文件,比如 css、js、image, (访问方式 http://localhost:8080/js/main.js)
templates:存放静态页面jsp,html,tpl
config:存放配置文件,application.properties
resources:
2、同个文件的加载顺序,静态资源文件
Spring Boot 默认会挨个从
META/resources > resources > static > public 里面找是否存在相应的资源,如果有则直接返回。
什么意思呢,就是比如你有个index.html文件,springboot默认放在以上文件夹是可以访问到的,而且是按照这个顺序访问。
案例:我在,resources,static ,public ,templates都放一个index.html文件,然后输入:localhost:8080,看访问的是哪个index.html

可以看出:首先访问就是resources里面的index.html
text文件默认是访问不了的,就算你的是localhost:8080/text/index.html也是访问不了的。

不过,你在application.properties配置如下,就可以访问了
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/test/

二、文件上传
一、war包方式进行上传
springboot文件上传的对象是MultipartFile,它是file的子类,源自
1)静态页面直接访问:localhost:8080/index.html
注意点:
如果想要直接访问html页面,则需要把html放在springboot默认加载的文件夹下面
2)MultipartFile 对象的transferTo方法,用于文件保存(效率和操作比原先用FileOutStream方便和高效)
案例:在static文件目录下,
upload.html
<!DOCTYPE html>
<html>
<head>
<title>uploadimg.html</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<!--涉及文件上传,这里就需要multipart/form-data-->
<form enctype="multipart/form-data" method="post" action="/upload">
文件:<input type="file" name="head_img"/>
姓名:<input type="text" name="name"/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
FileController类
package com.jincou.ocontroller;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import com.jincou.model.JsonData;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class FileController {
//文件放在项目的images下
private static final String filePath = "C:\\Users\\chenww\\Desktop\\springbootstudy\\springbootstudy\\src\\main\\resources\\static\\images\\";
@RequestMapping(value = "upload")
@ResponseBody
public JsonData upload(@RequestParam("head_img") MultipartFile file,HttpServletRequest request) {
//file.isEmpty(); 判断图片是否为空
//file.getSize(); 图片大小进行判断
String name = request.getParameter("name");
System.out.println("用户名:"+name);
// 获取文件名
String fileName = file.getOriginalFilename();
System.out.println("上传的文件名为:" + fileName);
// 获取文件的后缀名,比如图片的jpeg,png
String suffixName = fileName.substring(fileName.lastIndexOf("."));
System.out.println("上传的后缀名为:" + suffixName);
// 文件上传后的路径
fileName = UUID.randomUUID() + suffixName;
System.out.println("转换后的名称:"+fileName);
File dest = new File(filePath + fileName);
try {
file.transferTo(dest);
//上传成功
return new JsonData(0, fileName);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//上传失败
return new JsonData(-1, "fail to save ", null);
}
}
JsonData对象,用来返回状态
package com.jincou.model;
import java.io.Serializable;
public class JsonData implements Serializable {
private static final long serialVersionUID = 1L;
//状态码,0表示成功,-1表示失败
private int code;
//结果
private Object data;
//错误描述
private String msg;
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public void setCode(int code) {
this.code = code;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public JsonData(int code, Object data) {
super();
this.code = code;
this.data = data;
}
public JsonData(int code, String msg,Object data) {
super();
this.code = code;
this.msg = msg;
this.data = data;
}
}
效果:

这里面如果你想限制上传问价大小,可以在添加如下:
//文件大小配置,启动类里面配置
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
//单个文件最大
factory.setMaxFileSize("10240KB"); //KB,MB
/// 设置总上传数据总大小
factory.setMaxRequestSize("1024000KB");
return factory.createMultipartConfig();
}
总结:
1.其实在正式项目里,这里的文件上传地址不会是在本项目里,而是会指定一个文件服务器:
常用文件服务器:fastdfs,阿里云oss,nginx搭建一个简单的文件服务器
2.有关单个文件最大值,路径最好是配置在配置文件里,这样后期好维护。
热部署,配置文件使用
一、热加载
spring为开发者提供了一个名为spring-boot-devtools的模块来使Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Spring Boot应用。
devtools的原理
深层原理是使用了两个ClassLoader,一个Classloader加载那些不会改变的类(第三方Jar包),另一个ClassLoader加载会更改的类,称为restart ClassLoader,这样在有代码更改的时候,原来的restart ClassLoader 被丢弃,重新创建一个restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启时间。
官方地址:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#using-boot-devtools
实现热部署,首先要引入:spring-boot-devtools.jar包
核心依赖包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
添加依赖后,在ide里面重启应用,后续修改后马上可以生效
默认不被热部署的文件
1、/META-INF/maven, /META-INF/resources, /resources, /static, /public, or /templates
2、指定文件不进行热部署 spring.devtools.restart.exclude=static/**,public/**
在开发中,我们会思考一个问题?
如果你写一个逻辑代码,需要好几个文件,总不能你每保存一次就进行一次热部署,这里有个解决方法。
在application.properties添加手工触发重启
#指定某些文件不进行监听,即不会进行热加载 #spring.devtools.restart.exclude=application.properties #通过触发器,去控制什么时候进行热加载部署新的文件 spring.devtools.restart.trigger-file=trigger.txt
然后在src\main\resources目录下,添加trigger.txt文件
version=1
这样你每次改好代码,不会每次保存就热部署,而是改好代码后,改version=2就会进行热部署。
注意点:生产环境不要开启这个功能,如果用java -jar启动,springBoot是不会进行热部署的
二、SpringBoot注解把配置文件自动映射到属性和实体类实战
方式一、Controller上面配置
简介:讲解使用@value注解配置文件自动映射到属性和实体类
1、配置文件加载
方式一
1、Controller上面配置
@PropertySource({"classpath:resource.properties"})
2、增加属性
@Value("${test.name}")
private String name;
举例
上篇的文件上传的地址我是写死的。
这样显然不科学,这里改成写在1.application.properties配置文件里。
#文件上传路径配置 web.file.path=C:/Users/chenww/Desktop/springbootstudy/springbootstudy/src/main/resources/static/images/
2在FileController 类中
@Controller
@PropertySource({"classpath:application.properties"})
public class FileController {
//文件放在项目的images下
// private String filePath = "C:\\Users\\chenww\\Desktop\\springbootstudy\\springbootstudy\\src\\main\\resources\\static\\images\\";
@Value("${web.file.path}")
private String filePath;
总结:
1:@PropertySource代表读取哪个文件
2:@Value通过key得到value值
方式二:实体类配置文件
步骤:
1、添加 @Component 注解;
2、使用 @PropertySource 注解指定配置文件位置;
3、使用 @ConfigurationProperties 注解,设置相关属性;
4、必须 通过注入IOC对象Resource 进来 , 才能在类中使用获取的配置文件值。
@Autowired
private ServerSettings serverSettings;
案例:
1.在application.properties
#测试配置文件路径 test.domain=www.jincou.com test.name=springboot
2.创建ServerSettings实体
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
//服务器配置
@Component
@PropertySource({"classpath:application.properties"})
@ConfigurationProperties
public class ServerSettings {
//名称test.domain是key值
@Value("${test.domain}")
private String name;
//域名地址
@Value("${test.name}")
private String domain;
//提供set和get方法
}
三创建GetController
import com.jincou.model.ServerSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GetController {
//需要注入
@Autowired
private ServerSettings serverSettings;
@GetMapping("/v1/test_properties")
public Object testPeroperties(){
return serverSettings;
}
}
页面效果

其实上面还可以做个优化:
创建ServerSettings实体
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
//服务器配置
@Component
@PropertySource({"classpath:application.properties"})
@ConfigurationProperties(prefix="test")
//这里加了个test前缀
public class ServerSettings {
//这是不需要写vlaue标签,只要text.name去掉前缀test后的name和这里name相同,就会自动赋值
private String name;
//域名地址
private String domain;
//提供set和get方法
}
单元测试,全局异常
一、单元测试
1.基础版
1、引入相关依赖
<!--springboot程序测试依赖,如果是自动创建项目默认添加--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
2:关键注解:@RunWith @SpringBootTest
import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class) //底层用junit SpringJUnit4ClassRunner
@SpringBootTest(classes={SpringbootstudyApplication.class})//启动整个springboot工程
public class SpringBootTestDemo {
@Test
public void testOne(){
System.out.println("test hello 1");
TestCase.assertEquals(1, 1);
}
@Test
public void testTwo(){
System.out.println("test hello 2");
TestCase.assertEquals(1, 1);
}
@Before
public void testBefore(){
System.out.println("before");
}
@After
public void testAfter(){
System.out.println("after");
}
}
输出结果:

2.MockMvc
MockMvc类的使用和模拟Http请求实战
TestController
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("/vq/test")
public String getTest(){
return"我是测试返回值";
}
}
MockMvcTestDemo
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.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
/**
* 功能描述:测试mockmvc类
*
*/
@RunWith(SpringRunner.class) //底层用junit SpringJUnit4ClassRunner
@SpringBootTest(classes={SpringbootstudyApplication.class}) //启动整个springboot工程
@AutoConfigureMockMvc
public class MockMvcTestDemo {
@Autowired
private MockMvc mockMvc;
@Test
public void apiTest() throws Exception {
MvcResult mvcResult = mockMvc.perform( MockMvcRequestBuilders.get("/vq/test") ).
andExpect( MockMvcResultMatchers.status().isOk() ).andReturn();
int status = mvcResult.getResponse().getStatus();
System.out.println(status);
}
}
结果:返回200状态码

总结,关键注解:
@RunWith(SpringRunner.class) //底层用junit SpringJUnit4ClassRunner
@SpringBootTest(classes={SpringbootstudyApplication.class}) //启动整个springboot工程
@AutoConfigureMockMvc
二、配置全局异常
首先springboot自带异常是不友好的。
举例
@RequestMapping(value = "/api/v1/test_ext")
public Object index() {
int i= 1/0;
return new User(11, "sfsfds", "1000000", new Date());
}
页面

1、配置全局异常
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//添加全局异常注解
@RestControllerAdvice
public class CustomExtHandler {
private static final Logger LOG = LoggerFactory.getLogger(CustomExtHandler.class);
//捕获全局异常,处理所有不可知的异常
@ExceptionHandler(value=Exception.class)
//@ResponseBody
Object handleException(Exception e,HttpServletRequest request){
LOG.error("url {}, msg {}",request.getRequestURL(), e.getMessage());
Map<String, Object> map = new HashMap<>();
map.put("code", 100);
map.put("msg", e.getMessage());
map.put("url", request.getRequestURL());
return map;
}
}
在看页面:

关键注解:
@RestControllerAdvice //全局注解
@ExceptionHandler(value=Exception.class) //捕获不同异常,这里捕获是Exception异常,你也可以指定其它异常
2.自定义异常
在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。
- 所有异常都必须是 Throwable 的子类。
- 如果希望写一个检查性异常类,则需要继承 Exception 类。
- 如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。
1.自定义MyException异常
/**
* 功能描述:自定义异常类
*
*/
public class MyException extends RuntimeException {
private static final long serialVersionUID = 1L;
public MyException(String code, String msg) {
this.code = code;
this.msg = msg;
}
private String code;
private String msg;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
controller类
/**
* 功能描述:模拟自定义异常
*/
@RequestMapping("/api/v1/myext")
public Object myexc(){
//直接抛出异常
throw new MyException("499", "my ext异常");
}
页面
过滤器,监听器,拦截器
一、理解它们
看里十几篇博客,总算有点小明白,总的来讲,两张图可以让我看明白点。


通过两幅图我们可以理解拦截器和过滤器的特点
1、过滤器
过滤器是在请求进入tomcat容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
理解上面这句话我们就可以知道,进入servlet之前,主要是两个参数:ServletRequest,ServletResponse 那我们得到这两个测试可以干哪些事呢?
我们可以通过ServletRequest得到HttpServletRequest,此时你就可以对请求或响应(Request、Response)那就可以对对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息、字符集统一等一些高级功能。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。。它是随你的web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。(每次热部署后,都会销毁)。
2、拦截器
从上图我们可以看出过滤器只在servlet前后起作用,所以它既不能捕获异常,获得bean对象等,这些是只能是进入servlet里面的拦截器能过做到。拦截器中用于在某个方法或字段被访问之前,进行拦截然后,在之前或之后加入某些操作。比如日志,安全等。一般拦截器方法都是通过动态代理的方式实现。可以通过它来进行权限验证,或者判断用户是否登陆,或者是像12306 判断当前时间是否是购票时间。
对比一下其实我们可以发现,过滤器能做的事拦截器都能做,二拦截器做的事过滤器不一定做的了。
3、监听器
listener是servlet规范中定义的一种特殊类。用于监听servletContext、HttpSession和servletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件。用于在事件发生前、发生后做一些必要的处理。其主要可用于以下方面:1、统计在线人数和在线用户2、系统启动时加载初始化信息3、统计网站访问量4、记录用户访问路径。
常用的监听器 servletContextListener、httpSessionListener、servletRequestListener)
二、如何创建他们
1、过滤器
自定义Filter 使用Servlet3.0的注解进行配置第三步的@WebFilter就是3.0的注解
1)启动类里面增加 @ServletComponentScan,进行扫描
2)新建一个Filter类,implements Filter,并实现对应的接口
3) @WebFilter 标记一个类为filter,被spring进行扫描
urlPatterns:拦截规则,支持正则
4)控制chain.doFilter的方法的调用,来实现是否通过放行不放行,web应用resp.sendRedirect("/index.html");场景:权限控制、用户登录(非前端后端分离场景)等
application类
@SpringBootApplication
@ServletComponentScan
public class SpringbootstudyApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootstudyApplication.class, args);
}
}
LoginFilter过滤器
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
//过滤器拦截路径
@WebFilter(urlPatterns = "/api/*", filterName = "loginFilter")
public class LoginFilter implements Filter{
/**
* 容器加载的时候调用
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("拦截器进入========拦截器进入========");
}
/**
* 请求被拦截的时候进行调用
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截中========拦截中========");
HttpServletRequest hrequest = (HttpServletRequest)servletRequest;
HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper((HttpServletResponse) servletResponse);
if(hrequest.getRequestURI().indexOf("/index") != -1 ||
hrequest.getRequestURI().indexOf("/asd") != -1 ||
hrequest.getRequestURI().indexOf("/online") != -1 ||
hrequest.getRequestURI().indexOf("/login") != -1
) {
filterChain.doFilter(servletRequest, servletResponse);
}else {
wrapper.sendRedirect("/login");
}
}
/**
* 容器被销毁的时候被调用
*/
@Override
public void destroy() {
System.out.println("拦截器销毁========拦截器销毁========");
}
}
1、官网地址:https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-embedded-container-servlets-filters-listeners
二、监听器
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class RequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent sre) {
// TODO Auto-generated method stub
System.out.println("======销毁监听器========");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("======进入监听器========");
}
三、拦截器
CustomWebMvcConfigurer主拦截器需要:
1:添加@Configuration注解
2:实现WebMvcConfigurer接口
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
//主拦截器,根据拦截不同路径跳转不同自定义拦截器 (实现WebMvcConfigurer方法)
@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api1/*/**");
registry.addInterceptor(new TwoIntercepter()).addPathPatterns("/api2/*/**");
//.excludePathPatterns("/api2/xxx/**"); //拦截全部 /*/*/**
WebMvcConfigurer.super.addInterceptors(registry);
}
}
LoginIntercepter子拦截器
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class LoginIntercepter implements HandlerInterceptor{
/**
* 进入controller方法之前
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("LoginIntercepter------->preHandle");
// String token = request.getParameter("access_token");
//
// response.getWriter().print("fail");
return HandlerInterceptor.super.preHandle(request, response, handler);
}
/**
* 调用完controller之后,视图渲染之前
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("LoginIntercepter------->postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
/**
* 整个完成之后,通常用于资源清理
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("LoginIntercepter------->afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
TwoIntercepter同上
最后总解一下他们:
过滤器:用于属性甄别,对象收集(不可改变过滤对象的属性和行为)
监听器:用于对象监听,行为记录(不可改变监听对象的属性和行为)
拦截器:用于对象拦截,行为干预(可以改变拦截对象的属性和行为)
整合Mybaties增删改查
#数据驱动可配也可以不配,因为系统会自动识别 #spring.datasource.driver-class-name =com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/movie?useUnicode=true&characterEncoding=utf-8 spring.datasource.username =root spring.datasource.password =root #让控制台打印SQL语句,一般用于本地开发环境 mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl #springboot有自带数据源这个也可不配置 spring.datasource.type =com.alibaba.druid.pool.DruidDataSource
4.Springboot主类
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//@MapperScan会自动扫描里面的包,而且应该是可以自动给每个类装配一个Bean对象
@SpringBootApplication
@MapperScan("com.jincou.mapper")
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
5、UserMapper
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import com.jincou.model.User;
/**
* 功能描述:访问数据库的接口
*/
public interface UserMapper {
//推荐使用#{}取值,不要用${},因为存在注入的风险
@Insert("INSERT INTO user(name,phone,create_time,age) VALUES(#{name}, #{phone}, #{createTime},#{age})")
@Options(useGeneratedKeys=true, keyProperty="id", keyColumn="id") //keyProperty java对象的属性;keyColumn表示数据库的字段
int insert(User user);
//column指数据库中的列,property是指实体的属性名,如果一致就不需要写
@Select("SELECT * FROM user")
@Results({
@Result(column = "create_time",property = "createTime")
})
List<User> getAll();
@Select("SELECT * FROM user WHERE id = #{id}")
@Results({
@Result(column = "create_time",property = "createTime")
})
User findById(Long id);
@Update("UPDATE user SET name=#{name} WHERE id =#{id}")
void update(User user);
@Delete("DELETE FROM user WHERE id =#{userId}")
void delete(Long userId);
}
7、UserServiseImpl
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.jincou.mapper.UserMapper;
import com.jincou.model.User;
import com.jincou.service.UserService;
@Service
public class UserServiceImpl implements UserService{
//因为主类的@MapperScan方法,所以自动为UserMapper装配了一个userMapper对象
@Autowired
private UserMapper userMapper;
//这里你传过去的时候user的id为null,而insert之后传回回来的user会把数据库中的id值带回来,真强大
@Override
public int add(User user) {
userMapper.insert(user);
int id = user.getId();
return id;
}
}
8.Controller类
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.jincou.mapper.UserMapper;
import com.jincou.model.JsonData;
import com.jincou.model.User;
import com.jincou.service.UserService;
@RestController
@RequestMapping("/api/v1/user")
public class UserController {
//在UserServiceImpl定义了@Service实现类所以可以得到默认首字母小写的对象
@Autowired
private UserService userService;
@Autowired
private UserMapper userMapper;
/**
* 功能描述: user 保存接口
*/
@GetMapping("add")
public Object add(){
User user = new User();
user.setAge(11);
user.setCreateTime(new Date());
user.setName("张三");
user.setPhone("1880177");
int id = userService.add(user);
return id;
}
/**
* 功能描述:查找全部用户
* 这里和下面是直接调用跳过Servise层,直接到DAO层
*/
@GetMapping("findAll")
public Object findAll(){
return userMapper.getAll();
}
/**
* 查找单个用户
*/
@GetMapping("find_by_id")
public Object findById(long id){
return userMapper.findById(id);
}
/**
* 删除单个用户
*/
@GetMapping("del_by_id")
public Object delById(long id){
userMapper.delete(id);
return "";
}
/**
*更新用户
*/
@GetMapping("update")
public Object update(String name,int id){
User user = new User();
user.setName(name);
user.setId(id);
userMapper.update(user);
return "";
}
}
测试
1.准备好数据库数据:
#Sql脚本
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) DEFAULT NULL COMMENT '名称',
`phone` varchar(16) DEFAULT NULL COMMENT '用户手机号',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`age` int(4) DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;
2测试结果

插入用户,看后台的sql语句

Springboot整合redis
步骤讲解
1、第一步jar导入:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
如果你本地没有相应jar包,你可以在mevan存放jar包的库中,找到Setting文件,添加阿里云镜像,在跟新就可以下载相应jar包
<mirror>
<id>alimaven-central</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
第二步:application.properties配置
配置
第三步创建实体
User类
User类JsonData工具类实体
/**
* 这是后端向前端响应的一个包装类
* 一般后端向前端传值会有三个属性
* 1:响应状态
* 2:如果响应成功,把数据放入
* 3: 描述,响应成功描述,或者失败的描述
*/
public class JsonData implements Serializable {
private static final long serialVersionUID = 1L;
private Integer code; // 状态码 0 表示成功,1表示处理中,-1表示失败
private Object data; // 数据
private String msg;// 描述
public JsonData() {
}
public JsonData(Integer code, Object data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
}
// 成功,只返回成功状态码
public static JsonData buildSuccess() {
return new JsonData(0, null, null);
}
// 成功,传入状态码和数据
public static JsonData buildSuccess(Object data) {
return new JsonData(0, data, null);
}
// 失败,传入描述信息
public static JsonData buildError(String msg) {
return new JsonData(-1, null, msg);
}
// 失败,传入描述信息,状态码
public static JsonData buildError(String msg, Integer code) {
return new JsonData(code, null, msg);
}
// 成功,传入数据,及描述信息
public static JsonData buildSuccess(Object data, String msg) {
return new JsonData(0, data, msg);
}
// 成功,传入数据,及状态码
public static JsonData buildSuccess(Object data, int code) {
return new JsonData(code, data, null);
}
//提供get和set方法,和toString方法
}
第四步创建工具类
1、字符串转对象,对象转字符串工具类
import java.io.IOException;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* 字符串转对象,对象转字符串的工具类
* 因为StringRedisTemplate的opsForValue()方法需要key,value都需要String类型,所以当value值存入对象的时候
* 先转成字符串后存入。
*/
public class JsonUtils {
private static ObjectMapper objectMapper = new ObjectMapper();
//对象转字符串
public static <T> String obj2String(T obj){
if (obj == null){
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
//字符串转对象
public static <T> T string2Obj(String str,Class<T> clazz){
if (StringUtils.isEmpty(str) || clazz == null){
return null;
}
try {
return clazz.equals(String.class)? (T) str :objectMapper.readValue(str,clazz);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
2、封装Redis类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
/**
* 功能描述:redis工具类
* 对于redisTpl.opsForValue().set(key, value)进行了一次封装,不然每次都要这样保存值
* 而封装后只需:new RedisClient().set(key,value);
*/
@Component
public class RedisClient {
@Autowired
private StringRedisTemplate redisTpl; //jdbcTemplate
// 功能描述:设置key-value到redis中
public boolean set(String key ,String value){
try{
redisTpl.opsForValue().set(key, value);
return true;
}catch(Exception e){
e.printStackTrace();
return false;
}
}
// 功能描述:通过key获取缓存里面的值
public String get(String key){
return redisTpl.opsForValue().get(key);
}
}
第五步创建Controller类
RdisTestController
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.jincou.model.JsonData;
import com.jincou.model.User;
import com.jincou.until.JsonUtils;
import com.jincou.until.RedisClient;
@RestController
@RequestMapping("/api/v1/redis")
public class RdisTestController {
//得到redis封装类
@Autowired
private RedisClient redis;
//添加字符串
@GetMapping(value="add")
public Object add(){
redis.set("username", "xddddddd");
return JsonData.buildSuccess();
}
//通过key值得到value字符串
@GetMapping(value="get")
public Object get(){
String value = redis.get("username");
return JsonData.buildSuccess(value);
}
//将对象通过工具类转成String类型,存入redis中
@GetMapping(value="save_user")
public Object saveUser(){
User user = new User(1, "abc", "11", new Date());
String userStr = JsonUtils.obj2String(user);
boolean flag = redis.set("base:user:11", userStr);
return JsonData.buildSuccess(flag);
}
//通过key值得到value值,让后将value转为对象
@GetMapping(value="find_user")
public Object findUser(){
String userStr = redis.get("base:user:11");
User user = JsonUtils.string2Obj(userStr, User.class);
return JsonData.buildSuccess(user);
}
}
测试效果

命名规范:如果我们key按"base:user:11"这来命名,那么那么会自动创建文件夹格式,方便查看。

浙公网安备 33010602011771号