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类

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"这来命名,那么那么会自动创建文件夹格式,方便查看。
springBoot(1)--初步理解的更多相关文章
- 一些SpringBoot的初步理解
SpringBoot SpringBoot作为近几年很火的微服务框架,只需要简单的几个依赖,少量的配置,就可以使用它快速搭建一个轻量级的微服务,优点是简单.快速.大道至简,缺点是真的太单一,不适于项目 ...
- springBoot(1)---springboot初步理解
springboot初步理解 在没有用SpringBoot之前,我们用spring和springMVC框架,但是你要做很多比如: (1)配置web.xml,加载spring和spring mvc 2) ...
- javascript 原型及原型链的初步理解
最近折腾了好久,终于是把js里面的原型和原型链做了个初步的理解: 在这里,我打个比喻: 我(child),我妈constructor(构造函数)生了我:别人问我老妈跟谁生的我,于是此时我妈会指向我爸爸 ...
- Spring学习笔记--环境搭建和初步理解IOC
Spring框架是一个轻量级的框架,不依赖容器就能够运行,像重量级的框架EJB框架就必须运行在JBoss等支持EJB的容器中,核心思想是IOC,AOP,Spring能够协同Struts,hiberna ...
- Graph Cuts初步理解
一些知识点的初步理解_8(Graph Cuts,ing...) Graph cuts是一种十分有用和流行的能量优化算法,在计算机视觉领域普遍应用于前背景分割(Image segmentation).立 ...
- 非常易于理解‘类'与'对象’ 间 属性 引用关系,暨《Python 中的引用和类属性的初步理解》读后感
关键字:名称,名称空间,引用,指针,指针类型的指针(即指向指针的指针) 我读完后的理解总结: 1. 我们知道,python中的变量的赋值操作,变量其实就是一个名称name,赋值就是将name引用到一个 ...
- Mysql加锁过程详解(7)-初步理解MySQL的gap锁
Mysql加锁过程详解(1)-基本知识 Mysql加锁过程详解(2)-关于mysql 幻读理解 Mysql加锁过程详解(3)-关于mysql 幻读理解 Mysql加锁过程详解(4)-select fo ...
- 关于THINKPHP5模型关联的初步理解
初步理解的意思是,使用最常用的关联模型,然后可以正常运行 还是打个比方 文章表 和文章分类表 一个文章分类可以有多个文章 所以 文章分类模型和文章建立 hasMany的关联 而文章和文章分类表则 ...
- spfa+差分约束系统(C - House Man HDU - 3440 )+对差分约束系统的初步理解
题目链接:https://cn.vjudge.net/contest/276233#problem/C 题目大意:有n层楼,给你每个楼的高度,和这个人单次的最大跳跃距离m,两个楼之间的距离最小是1,但 ...
- Android-自定义控件-继承View与ViewGroup的初步理解
继承View需要走的流程是: 1.构造实例化, public ChildView(Context context, @Nullable AttributeSet attrs) 2.测量自身的高和宽on ...
随机推荐
- AlignSum:数据金字塔与层级微调,提升文本摘要模型性能 | EMNLP'24
来源:晓飞的算法工程笔记 公众号,转载请注明出处 论文: AlignSum: Data Pyramid Hierarchical Fine-tuning for Aligning with Human ...
- Abp Vnext 中如何统一接口返回值
ABP Vnext Vue 的实现 https://github.com/WangJunZzz/abp-vnext-pro 在使用 abp 的过程中,如果提供给第三方接口要实现返回值统一需要怎么做? ...
- npm : 无法加载文件 D:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本
升级node和npm之后,npm run dev 启动一个Vue项目,报错如下: npm : 无法加载文件 D:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本. ...
- Solr学习总结-Facet
返回查询集合中指定field的统计情况,例如找到city一样的文档数目: 加入文档 <add> <doc> <field name="id">1 ...
- 成为Java GC专家系列(3) — 如何优化Java垃圾回收机制
本文是成为Java GC专家系列文章的第三篇.在第一篇<成为JavaGC专家Part I - 深入浅出Java垃圾回收机制>中我们学习了不同GC算法的执行过程,GC是如何工作的,什么是新生 ...
- Git 克隆部分文件
使用 sparse-checkout (推荐) git clone \ -b master \ --depth=1 \ --filter=blob:none \ --sparse \ <repo ...
- RocksDB 内存超限问题剖析
作者:来自 vivo 互联网服务器团队- Zeng Luobin 在使用 RocksDB 存储引擎的过程中,有部分开发者遇到了内存使用超出预期的情况.本文针对这一问题展开了深入分析,从内存使用原理.R ...
- Rocky Linux9.5部署k8s1.28.2+docker
yum换源sed -e 's|^mirrorlist=|#mirrorlist=|g' \ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdi ...
- 《数据万象带你玩转视图场景》第一期:avif图片压缩详解
前言 随着硬件的发展,不管是手机还是专业摄像设备拍出的图片随便可能就有几M,甚至几十M,并且现在我们处于随处可及的信息海洋里,海量的图片带来了存储问题.带宽问题.加载时延问题等等.对图片信息进行有效的 ...
- IOS 越狱
iOS越狱 palera1n palera1n工具支持iOS 15.0 - 16.4.1版本的越狱 支持设备,最高支持到A11芯片 iPhone 8.8P.X iPad 5 .6.7,iPad Pro ...