简介
Inversion of Control 控制反转,
又称为依赖注入 DI ——Dependency Injection。
解决痛点
大型程序之间的高耦合性与冗余性,共享组件、统一销毁。
底层原理
XML解析、工厂模式、反射。
IOC容器底层就是对象工厂。
意义
传统的应用程序中,控制权在程序本身,程序的控制流程完全由开发者控制。在IoC模式下,控制权发生了反转,即从应用程序转移到了IoC容器,所有组件不再由应用程序自己创建和配置,而是由IoC容器负责,这样,应用程序只需要直接使用已经创建好并且配置好的组件。为了能让组件在IoC容器中被“装配”出来,需要某种“注入”机制,其将组件的创建+配置与组件的使用相分离,并且,由IoC容器负责管理组件的生命周期。
总结:Ioc意味着将你设计好的对象交给容器控制,而不是按照传统在对象内部直接控制
小点:
// 从 ApplicationContext里面获取 Bean
UserMapper mapper=context.gerBean(UserMapper.class);
简介:
SpringBoot支持面向切面编程,其可以在不改动原代码的动态添加代码、动态删去代码。这在日志记录、安全检查和事务等方面很有用。AOP技术本质上就是一个动态代理,让我们可以把一些常用功能如权限检查、日志、事务从业务方法中剥离出来。
题外话:
Spring的 AOP实现基于 JVM的动态代理,所以我们有时候也会这样子形容——AOP代理、AOP代理对象,意即AOP代理了本来的类对象。
在 Java平台上对于AOP的织入,一共有三种方式:
原理解释:
Spring对接口类型使用JDK动态代理,对普通类使用CGLIB创建子类,在之后使用的也是它的子类,但对于用户来说是无感的。如果一个Bean的class是final,Spring将无法为其创建子类。
// 原类为 UserTest,打印出来可以看到被 Spring enhance
// 并非原类,为其子类。
class com.thinkstu.test.UserTest$$EnhancerBySpringCGLIB$$217a2220
AOP:Aspect-Orinented Programing 面向切面编程。
OOP:Object-Oriented Programming面向对象编程,封装、继承、多态。
常用术语:
AOP的使用:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
切入:新定义类,并 @Aspect总开关注解,切入点注解。
@Aspect //表示AOP
@Component
public class UsersAspect {
@Pointcut("execution(* com.thinkstu.controller.*.*(..))")
public void cut() {
}
@Before(value = "cut()")
public void before(JoinPoint joinPoint) {
// 返回方法名
String name = joinPoint.getSignature().getName();
System.out.println("before开始执行----" + name);
}
@After(value = "cut()")
public void after(JoinPoint joinPoint) {
System.out.println("after开始执行----");
}
@AfterReturning(value = "cut()", returning = "result")
public void getResult(JoinPoint joinPoint, Object result) {
// 方法返回值
System.out.println("after开始执行----" + result);
}
@AfterThrowing(value = "cut()", throwing = "ex")
public void afterThrowing(Exception ex) {
System.out.println("发生异常------afterThrowing" + ex);
}
@Around(value = "cut()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around优先执行的语句----------");
pjp.proceed();
System.out.println("around中方法已执行----------");
}
}
SSM整合指 Spring、SpringMVC、Mybatis的整合。
说明
原生接口。当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中。
通过 HttpServletRequest我们可以获得很多信息。
部分功能
提示:
获取全部请求信息应该使用 RequestEntity,而不是HttpServletRequest。
单纯简单获取请求体应该使用 @RequestHeader注解,而不是HttpServletRequest。
主要感觉 HttpServletRequest有点难用。
原生方式控制返回,但是一般不这样。
Cookie与 Session的区别:Session比Cookie安全
Cookie是客户端技术,存储在客户端。Session是服务器端技术,存储在服务端。
使用原因
HTTP 是无状态协议,它不能以状态来区分和管理请求和响应,也就是说服务器单从网络连接上无从知道客户身份。于是我们可以给客户端颁发通行证,如此服务端便能识别客户的身份,这就是 Cookie的工作原理。
Cookie是服务器存储在本地机器上的一小段文本。是客户端保存用户信息的一种机制,用来记录用户的一些信息,并随着每次请求发送到服务器。
Cookie会根据响应报文里的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie。当下次客户端再向服务端发起请求时,客户端会自动在请求报文中加入Cookie值之后发送出去。然后服务器端会根据记录,得到之前的最后状态信息。
Max-age与 Expires的区别
Expires和max-age都可以用来指定文档的过期时间,但是二者有一些细微差别。
Expires表示绝对时间,HTTP 1.0开始使用。Max-age表示相对时间,HTTP 1.1开始使用。
限制情况
单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能超过3K。
思想
当用户第一次访问网站时,网站会为用户生成唯一的 Session ID值,而后 Session会自动跟随响应报文 set-Cookie返回给客户端,所以可以说 Session的设置在一定程度上依赖于 Cookie。可以把Session ID 想象成一种用以区分不同用户的唯一Id。
强依赖 Cookie与弱依赖
当我们完全禁掉浏览器的cookie的时候,服务端的session可能不能正常使用。这取决于当前环境中 Session对 Cookie的依赖程度,通过规避写法可以避免强依赖。比如当禁用 Cookie时,PHP会自动把Session ID附着在URL中,继续正常使用。
这是一个大工程。
在 Spring中,由于其生命周期过于复杂,所以 Spring没有按惯例为所有阶段单独定义方法。
其使用事件监听器,我们只需要监听被干预的阶段即可(继承接口实现)。
优点表现:统一了管理事件流程,并用泛型区分阶段。
<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.0modelVersion>
<groupId>com.companyname.project-groupgroupId>
<artifactId>projectartifactId>
<version>1.0version>
project>
pom包细究:
总体结构(四部分),此为阿里云下载的 SpringBoot程序结构,官方与此稍有不同。
项目的总体信息
maven依赖库
maven依赖库设置
构建插件
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.80version>
dependency>
(Spring官方对 fastJSON的支持度很低,自行配置编码格式等内容)
@Configuration
class MyFastJsonConfig {
@Bean
FastJsonHttpMessageConverter fastJsonHttpMessageConverter(){
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setCharset(Charset.forName("UTF-8"));
config.setDateFormat("yyyy-MM-dd");
config.setSerializerFeatures(
SerializerFeature.WriteClassName,
SerializerFeature.WriteMapNullValue,
SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullStringAsEmpty
);
converter.setFastJsonConfig(config);
return converter;
}
}
server:
port: 80
servlet:
encoding:
force-response: true
简介:
CORS,Cross-Origin Resource Sharing,是由 W3C制定的一种跨域资源共享技术标准,其目的是为了解决前端的跨域请求。它允许浏览器向跨源服务器,发出 XMLHttpRequest请求,从而克服了 AJAX只能同源使用的限制。
特征:
其特征是浏览器在发送请求时会携带 Origin标识,因为“ 跨域 ”。
服务器如果支持跨域请求,则会检查 client所携带的 Origin正确性,作出相应回应。如果 oringin指定的域名在许可范围内,服务器返回的相应数据则会多出几个头信息字段。
Spring全称: Spring Framework
Annotation:基于注解的方式 @Component。当我们给类注解时,默认 Bean的命名空间为小写开头的全类名,如 UserMapper则为 userMapper,当然我们也可以指定 Bean命名空间。
其实总的来说,配置 Bean的方式有很多种,在SpringBoot的学习过程中我知道起码有七种。但是在日常的使用中普遍的也就两种:@Component注解或者 @Bean注解。
说明
注解的方式需要事先开启包扫描 @ComponentScan注解。
IDEA使用技巧
当显示这个小图标表示注解已生效,点击可跳转至 @Autowired被注入的地方。
注意:
当 Bean被创建时,会首先默认调用其无参构造方法。
当为饿汉模式时,运行即调用;当为懒汉模式时,使用时才调用。
SpringBoot如何设置在创建时调用有参构造方法?
@Configuration + @Bean
采用配置类 @Configuration + @Bean的方式。第三个类可以指在所导入的 jar包中的类,它原来不是 Bean或者我们需要去配置它,但是我们并不能直接的去改写它,因为继承太过于麻烦、而且有时 jar中的类会被定义为 final无法继承。
@Configuration
public class CustomConfig {
@Bean
RedisTemplate getRedisTemplate(){
return new RedisTemplate();
}
}
当我们创建 Bean时,默认会为我们创建单例 Singleton的实例:即容器初始化时创建 Bean,容器关闭前销毁 Bean。
Spring默认类型是 singleton,几乎90%以上的业务使用单实例就可以。
Singleton的优点是效率高;缺点是可能会引发单线程下的线程安全问题。
Prototype的优点是不会触发单线程安全问题;缺点是每次连接请求都会创建 bean实例,请求数越多性能越低。而且因为创建的实例导致频繁垃圾回收,GC的时长也相应增加。(garbage cycle)
多实例的创建:
@Scope(value = "prototype")
@Scope(value = "singleton")
@Scope(value = "request") //一次http请求内有效
@Scope(value = "session") //一个用户会话内有效
@Scope(value = "globalSession") //全局会话内有效
自动注入本身属性: require = true
实现功能:在注入时忽略报错,有则加载、无则使用默认值。
// 此处并不一定会加载 222,而是该 Bean不存在时才会加载 222,注意这种写法。
@Autowired(required = false)
User user = new User(222);
123
属性 | 说明 |
---|---|
@Autowired | 根据属性类型自动装配 |
@Qualifier | 结合@ Autowired根据属性名称自动装配 |
@Resource | 可以根据属性类型或属性名称进行注入 |
@Value | 普通类型属性注入 |
(但是 Spring官方不推荐使用 @Resource,因为注解并非 Spring官方开发,而是属于 Javax——Java扩展包之中的内容)
简单使用:
配置同类型不同名的 Bean对象。
@Configuration
public class CustomConfig {
@Bean
@Primary // 默认 Bean
UserService get_01() {
return new UserServiceImpl();
}
@Bean("other") // 需指定名称才能导入
UserService get_02() {
return new UserServiceImpl();
}
}
利用 @Autowired + @Qualifier 进行指定Bean的注入。
@Autowired
@Qualifier("other")
UserService service;
Bean也含有生命周期,利用注解(于方法上)我们可以对其进行控制,分别在其创建后、销毁前。
@PostConstruct与 @PreDestroy
@PostConstruct
void initial(){
System.out.println("创建后");
}
@PreDestroy
void destroy(){
System.out.println("销毁前");
}
即 @Conditional(OnSmtpEnvCondition.class)的形式。
使用条件注解,使我们能够更加灵活的装载 Bean。
// 如果Spring中不存在 UsersController Bean,就加载配置
@Configuration
@ConditionalOnMissingBean(Cat.class)
public class Test {
@Bean
public Dog getMsg(){
return new Dog();
}
}
@ConditionalOnBean(name = "com.test.controller.UsersController")
@Component("jerry")
public class Cat {
}
( 比如 @ConditionalOnMissingClass(com.pojo.yyoo) ,当不存在此类时,条件为真。)
Spring在注入一对象时,对象里的变量是如何被赋值的呢?
Spring会调用这些变量的 set___ ( ) 方法从而为这些变量赋值,我们可以控制此流程。
即存在于 XML配置文件中的扩展写法(了解即可)。
实现步骤:
利用ApplicationContext获取的对象,最后需要手动的去关闭它。
两种方法:
Spring中拥有两种方式(并非方法)。
按 ID名字获取
在SpringBoot中,根据 @Autowired + @Qulifier 获取
按类型获取
app.getBean("ByID");
app.getBean(___.class);
两种注解。
@Import(ConfigUser.class)
JavaBean分为两类:
这些衍生出来的注解都是同一种东西的不同表现形式,作用完全一样、只是为了给程序员作区分使用。
注解@ | 标识为 |
---|---|
Component | 一般组件 |
Controller | 控制器 |
Service | 事件处理器 |
Repository | 持久层处理器 |
全称:Representational State Transfer,表现形态转换。
分类(Spring共支持8种)
GET(查询)、POST(新增、保存)、PUT(修改)、DELETE(删除)
说明:
路径占位符
@GetMapping("/{name}/{pass}")
void login(@PathVariable("name") String name){
System.out.println("login");
}
功能 | URL 地址 | 请求方式 |
---|---|---|
访问首页 | / | GET |
查询全部数据 | /employee | GET |
删除 | /employee/2 | DELETE |
跳转到添加数据页面 | /toAdd | GET |
执行保存 | /employee | POST |
跳转到更新数据页面 | /employee/2 | GET |
执行更新 | /employee | PUT |
该注解属性有六种,分别为 value、method、produces、consumes、header、params。
其中注意 headers作用的是请求头,而 params作用的则是请求参数。
value
指定请求的实际地址。
method
指定请求的method类型, GET、POST、PUT、DELETE等。
produces
指定返回内容的类型,只有当 request请求头中 Accept属性包含该 produces指定的类型才能返回数据成功,例如:accept:text/xml。
cousumes
指定request请求提交的内容类型(Content-Type),例如application/json, text/html等。
headers
指定request请求中必须包含某些指定的请求头header的值,才能让该方法处理请求。
例如:Host=127.0.0.1
“header”:要求请求映射所匹配的请求必须携带header请求头信息
“!header”:要求请求映射所匹配的请求必须不能携带header请求头信息
“header=value”:要求请求映射所匹配的请求必须携带header请求头信息且header=value
“header!=value”:要求请求映射所匹配的请求必须携带header请求头信息且header!=value
params
指定request请求地址中必须包含某些参数值,方法才处理,否则拒绝处理。
----params = “key1”==:表示请求必须包含名为key1的请求参数;
----params = “!key1”:表示请求不能包含名为key1的请求参数;
----params = “key1 != value1”:表示请求必须包含名为key1的请求参数,但是其值不能是value1;
----params = {“key1 = value1”, “key2”}:==表示请求必须包含名为key1和key2两个请求参数,且key1的值必须为value1;
params = {"username","password!=123456"}
SpringMVC支持 ant风格的路径,即支持 ant风格的通配符,三种。
符号 | 表意 |
---|---|
? | 单个字符 |
* | 0个或多个字符 |
** | 一层或者多层目录 |
本节将展示当我们不采用 RESTful风格时的情况。
一般使用(参数同名时)
形参参数名应与浏览器传过来的参数名一样,并不使用 @PathVariable路径参数注解。
在该例中,浏览器会跳转至 /static/uuu.html页面(MVC自动解析跳转)。
可变长参数
最后环节,使用数组接收可变长参数。
@RequestParam参数
当形参参数名与浏览器传过来的参数不一致时,使用注解来指定。
required:是否必须
name:名字
defaultValue:当不存在时,则使用默认值。(结合 required = false 使用)
实例:在 url的跳转中实现数据的共享。
要求:既要实现完整功能,又要范围最小。
5种方式
说明
ModelAndView 统一实现了 Model对象和 View对象的功能。
Model 主要用于向请求域共享数据,其本身是 Map的子类,拥有相应功能。
View 主要用于设置视图实现页面跳转。
注意
当未配置其他解析器或者为使用 @ResponseBody注解时,默认使用的是SpringMVC解析器,而SpringMVC解析器会返回 ModelAndView对象。
实现原理
当控制器处理完请求后,通常控制器会将包含视图名称以及一些模型属性的 ModelAndView对象返回给 DispatcherServlet。因此,在控制器中会构造一个 ModelAndView
对象
数据共享:直接使用方法。
addObject(String attributeName, Object attributeValue)
@GetMapping
ModelAndView get() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("uuu.html");
return modelAndView;
}
简介
正式名称:HttpMessageConverter 报文信息转换器。
将请求报文转换为Java对象,或将Java对象转换为响应报文。
四种类型:
@RequestBody
该注解加在Controller 的处理方法的形参上,作用是将json格式的数据转为java对象。
作用于 Post请求,获取请求体。
@RequestBody String requestBody
@RequestBody User user_date
RequestEntity对象
获取的是整个请求头+请求体,getBody( ) 获取请求体,getHeaders( )获取请求头。
**需要理解的是,HttpServletRequest是 Servlet技术,而 RequestEntity是 SpringMVC技术。**使用 RequestEntity而不使用 HttpServletRequest。
用法:只要控制器方法的形参中设置该类型,其就会自动赋值。
public String test(RequestEntity reqEntity){
//
}
@ResponseBody
该注解使用在Controller 方法上的 。将方法的返回值通过适当的转换器(如 Jackson)转换为指定的格式之后,写入到 response 对象的 body 区,通常用来给客户端返回 JSON 数据或者是 XML 数据。
当方法上面没有写 ResponseBody 时,底层会将方法的返回值封装为 ModelAndView 对象(原此);需要注意的是,在使用此注解之后不会再走试图处理器,而是直接将数据写入到输入流中,他的效果等同于通过 response 对象输出指定格式的数据。
ResponseEntity对象
可以定义返回的 HttpStatus(状态码)和 HttpHeaders(响应头) 和响应体 body,当形参出现此时,ModelAndView失效、@ResponseBody注解也失效。
@RequestMapping("/downExcel")
@ResponseBody
public String downExcel(HttpServletResponse response) {
// response逻辑操作
OutputStream os = response.getOutputStream();
return ""
}
用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器。
headers.add("Content-Disposition", "attachment;filename=1.jpg");
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
ServletContext servletContext = session.getServletContext();
//获取服务器中文件的真实路径
String realPath = servletContext.getRealPath("/static/img/1.jpg");
InputStream is = new FileInputStream(realPath);
byte[] bytes = new byte[is.available()];
//将流读到字节数组中
is.read(bytes);
//创建HttpHeaders对象设置响应头信息
MultiValueMap<String, String> headers = new HttpHeaders();
//设置要下载方式以及下载文件的名字
headers.add("Content-Disposition", "attachment;filename=1.jpg");
HttpStatus statusCode = HttpStatus.OK;
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
//关闭输入流
is.close();
return responseEntity;
}
实践:
以上代码我在 IDEA与服务器上并未跑通,于是我尝试了别的方法。
需要说明的是:所有资源都放在/resource/static/
里。
@RestController
@RequestMapping("/download")
public class DownloadController {
@GetMapping("{fileName}")
ResponseEntity down(@PathVariable("fileName") String fileName) throws Exception {
InputStream file = ClassUtils.getDefaultClassLoader()
.getResourceAsStream("static/" + fileName);
byte[] data = new byte[file.available()];
file.read(data);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition",
"attachment;filename=" + fileName);
ResponseEntity responseEntity =
new ResponseEntity<>(data, headers, HttpStatus.OK);
return responseEntity;
}}
IDEA跑通,服务器未跑通。
在路径两处多了感叹号 !
,暂时不明白原因是什么。
String realPath =
ResourceUtils.getURL("classpath:static/").getPath()+ fileName;
本质:文件复制。
上传功能必需请求头:
multipart/form-data,即标明为以二进制方式上传数据,而不是key-value。
<form method="post" enctype="multipart/form-data" action="/upload">
图片:<input type="file">
<input type="submit">
</form>
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.1version>
dependency>
@RequestMapping("/testUp")
public String testUp(MultipartFile photo, HttpSession session) throws IOException {
//获取上传的文件的文件名
String fileName = photo.getOriginalFilename();
//处理文件重名问题,UUID
String hzName = fileName.substring(fileName.lastIndexOf("."));
fileName = UUID.randomUUID().toString() + hzName;
//获取服务器中photo目录的路径
ServletContext servletContext = session.getServletContext();
String photoPath = servletContext.getRealPath("photo");
File file = new File(photoPath);
if(!file.exists()){
file.mkdir();
}
String finalPath = photoPath + File.separator + fileName;
//实现上传功能
photo.transferTo(new File(finalPath));
return "success";
}
简单实践
该案例会将文件上传至与当前项目总文件夹 平齐的文件夹。
@RestController
@RequestMapping("/upload")
public class UploadController {
@PostMapping
String upload(MultipartFile file, HttpSession session) throws IOException {
String filename = file.getOriginalFilename();
String fileType = filename.substring(filename.lastIndexOf("."));
filename = filename.substring(0,filename.indexOf("."))+ "-"
+ UUID.randomUUID().toString()+fileType;
String realPath = ResourceUtils.getURL("images").getPath();
File io_file=new File(realPath);
if (!io_file.exists()){
io_file.mkdirs();
}
file.transferTo(new File(finalPath));
return "success";
}}
@RequestParam,@PathVariable 之间的区别。
@RequestParam 和 @PathVariable 注解都是用于从 request中接收请求,两个都可以接收参数。关键点不同的是 @RequestParam 是从request里面拿取值,而 @PathVariable 是从一个 URI模板里面来填充。
用@RequestParam:
/login?name=uu&pass=123
用@PathVariable:
/login/uu/123
简介:
SpringMVC视图的种类很多,默认有转发视图和重定向视图。
但这必须不能存在@ResponseBody注解。
存在@ResponseBody注解时,就关乎SpringBoot下页面的跳转问题,具体使用 ModelAndView。
关注点:Themleaf好像已经很少使用。
转发视图
SpringMVC中默认的转发视图是 InternalResourceView。
当控制器方法中所设置的视图名称以"forward:"为前缀时,会创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:"去掉,剩余部分作为最终路径通过转发的方式实现跳转
@RequestMapping("/testForward")
public String testForward(){
return "forward:/testHello";
}
重定向视图
SpringMVC中默认的重定向视图是 RedirectView。
当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最终路径通过重定向的方式实现跳转
@RequestMapping("/testRedirect")
public String testRedirect(){
return "redirect:/testHello";
}
**前置知识:**SpringMVC常用组件
作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
作用:根据请求的url、method等信息查找Handler,即控制器方法
作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
作用:通过HandlerAdapter对处理器(控制器方法)进行执行
作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView
作用:将模型数据通过页面展示给用户
SpringMVC的执行流程:
用户向服务器发送请求,请求经过Filter后被 SpringMVC 前端控制器 DispatcherServlet捕获。
DispatcherServlet对请求 URL进行解析,得到请求资源标识符 URI,判断请求 URI对应的映射:
不存在
判断是否配置了mvc:default-servlet-handler
没配置:则控制台报映射查找不到,客户端展示404错误
有配置:则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404错误
存在(此处的 Handler为 Controller的同一对象不同说法)
根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以 HandlerExecutionChain执行链对象的形式返回。
DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter。
如果成功获得 HandlerAdapter,此时将开始执行拦截器的 preHandler(…)方法【正向】
提取 Request中的模型数据,填充Handler入参,开始执行 Handler方法,处理请求。在填充 Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
a) HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
b) 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
c) 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
d) 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。
此时将开始执行拦截器的postHandle(…)方法【逆向】。
根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model和View,来渲染视图。
渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。
将渲染结果返回给客户端。
简介:
默认配置说明
路径:classpath/template/____,后缀 html。
实现步骤:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
spring:
thymeleaf:
prefix: classpath:/template/
encoding: UTF-8
suffix: .html
实现说明:
在 cotroller中使用后,会默认返回 ModelAndView对象。
SpringMVC返回的也是 ModelAndView对象,两者同为视图解析器。
**static与 template目录:**static中的资源不受保护,可以直接通过 url定位来访问,而templates中的资源是受保护的。
SpringBoot工程在IDEA下需要联网进行。
SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化Spring应用的初始搭建以及开发过程。
SpringBoot只是简化Spring与SpringMVC的简化开发,MybatisPlus也是在简化Mybatis,本质还是SSM框架。
Spring Boot 不支持同时在配置中启动 HTTP HTTPS 。
一些专业名词
三种内嵌的数据源
数据源默认存在的,并不一定需要 Druid。
三种内嵌数据库(了解)
不过到真正上线的时候还是要切换到正式数据库,而且体验并不是很好,弃用。
MyBatis是一个基于 Java的、封装了 JDBC的持久层框架,其底层使用 JDBC来编写。
JS等前端库可通过 pom导入。
<dependency>
<groupId>org.webjarsgroupId>
<artifactId>vueartifactId>
<version>2.6.14version>
dependency>
Controller路径命名规则:
常用复数形式表示,如 users、employees等。
配置文件放在哪?
在Maven的结构下,配置文件均放在resource目录里。
yml配置信息如何记?
只需要你记得其中几个关键字,然后在 IDEA中敲一敲就能知道个大概。
未知编程思想
当遇到陌生方法调用时,只需观察其形参与返回值,在大多数情况下便可了解其用法。
html表单说明
html中的 form表单只能发送 Get或者 Post请求,并不能发送其他请求。
Tomcat思想:万物皆对象。
JSON数据格式说明:一共只有两种格式。
- 对象:{ }
- 数组:[ ]
**long类型**本身描述的时间单位为**毫秒ms**,熟记。
├── HELP.md
├── README.md
├── catcat.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── thinkstu
│ │ └── catcat
│ │ └── CatcatApplication.java
│ └── resources
│ ├── application.properties
│ ├── static
│ └── templates
└── test
└── java
└── com
└── thinkstu
└── catcat
└── CatcatApplicationTests.java
部分浏览器只支持发送 get和 post请求,那么在 SpringBoot中该如何发送 put和 delete请求呢?
SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为 DELETE 或 PUT 请求,SpringBoot中默认存在此配置类。
使用要求:
满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数_method的值,因此请求参数_method的值才是最终的请求方式。
简介:
jar包和war包都可以看成压缩文件,都可以用解压软件打开,jar包和war包都是为了项目的部署和发布,通常在打包部署的时候,会在里面加上部署的相关信息。
简单区别:
根本区别:
JAR文件的目的是把类和相关的资源封装到压缩的归档文件中,而对于WAR文件来说,一个WAR文件代表了一个Web应用程序,它可以包含 Servlet、HTML页面、Java类、图像文件,以及组成Web应用程序的其他资源,而不仅仅是类的归档文件。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jettyartifactId>
dependency>
<jetty.version>9.4.35.v20201120jetty.version>
简介:
位于主启动程序上,负责配置主程序。
其实是一个 SpringBoot Configuration( SpringBoot Configuration下面是 @Configuration)。
@SpringBootApplication
public class Test01Application {
public static void main(String[] args) {
SpringApplication.run(Test01Application.class, args);
}
}
简介:
范例:
加载名为users的这个Bean的cycle属性值
@Scheduled(cron = "0/#{users.cycle} * * * * ?")
@Data
@Component("users")
public class Users{
Integer cycle=10;
}
@ControllerAdvice :全局数据处理,是@Controller 的加强版。
@ControllerAdvice 主要用来处理全局数据,一般搭配@ExceptionHandler、@ModelAttribute 及@InitBinder 使用。而RESTControllerAdvice就是Restful风格的ControllerAdvice;
java -jar xxx.java
--server.port 8080
有时我们会为了安全,禁止其他人在运行我们的程序时添加临时属性。
方式:阻止main主程序中的args参数传到SpringApplication。
name: "/t name /n"
#表示对象,多实例(数组)用 - 符号分隔
users:
-
name: zhangsan
age: 22
city: 北京
-
name: wangwu
age: 23
city: 海南
#或者
users:
- name: zhangsan
age: 22
city: 北京
- name: wangwu
age: 23
city: 海南
#或者 (注:外层中括号表数组,里层大括号表具体对象)
users: users2: [{name: zhangsan,age: 22},{name: wangwu,age: 23}]
name: duck
users: ${name}
version: @project.version@
表示获取该程序的version属性,@ @包裹、输入会有提示。
简介:
松散绑定是 Spring为了兼容各种编程爱好者而制定的规则。
我们并不需要使用,但是要了解、知道它的存在,其有时会导致程序出现 error。
注意点:
范例:
yml中写的是 dataSource,但是在代码中以下形式都能绑定上数据。
@ConfigurationProperties(prefix = "datasource")
@ConfigurationProperties(prefix = "Data_Source")
@ConfigurationProperties(prefix = "Data-Source") // 羊肉串模式
//等等
在 SpringBoot条件下,利用 ModelAndView实现。
@RequestHeader,Spring中常用方式,非原生的方式。
经过观察,其注解的参数与 @RequestParam一样。
@CookieValue,Spring中常用方式,非原生的方式。
@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
SpringBoot默认的编码格式是 UTF-8 (写在底层源码中)。
有三种方式可以定制编码格式。
yml配置
直接查找 endoding就可以显现所有的内容。
server:
servlet:
encoding:
charset: UTF-8
Filter 过滤器配置
原理:Filter是浏览器发送的请求接触到的第一层服务器端应用。 (代码省略)
三个邮件协议
POP3与IMAP的不同点:**首先要得知,**我在这里所说的采用邮件协议为,全部在第三方软件中采用。采用POP3时,邮件删除等操作不会同步,即使你在第三方邮件系统删除了某封邮件,但是在原邮件系统中并不会执行删除操作。而采用IMAP就是为了改进这一点,实现了同步的操作。
简单实现三步走:
范例:
发送简单邮件
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-mailartifactId>
dependency>
spring:
mail:
host: smtp.qq.com
username: [email protected]
password: "Authorized code"
default-encoding: UTF-8
@Autowired
JavaMailSender sender;
@Test
void sendEmail(){
SimpleMailMessage msg = new SimpleMailMessage();
String from="Your [email protected]";
msg.setFrom(from+"(自定义发送昵称)"); //小括号里有内容~
msg.setTo("To [email protected]");
msg.setSubject("标题");
msg.setText("内容");
sender.send(msg);
}
**发送复杂邮件:**html格式、附件等
@Autowired
JavaMailSender sender;
@org.junit.jupiter.api.Test
void sendEmail() throws MessagingException {
MimeMessage msg= sender.createMimeMessage();
MimeMessageHelper msgHelper=new MimeMessageHelper(msg,true);
msgHelper.setFrom("Your [email protected](哇哇哇)");
msgHelper.setTo("To [email protected]");
msgHelper.setText("链接",true);
String file="src/main/resources/application.yml";
msgHelper.addAttachment("application.yml", new File(file));
sender.send(msg);
}
邮件中的SSL加密
发送邮件或者接受邮件时我们可以配置SSL加密,具体要去邮件提供商那边获取。
例如对于腾讯,SSL端口为465或者587,首先开启 SSL然后再配置端口。
@EnableScheduling
1
@Component
public class Test {
@Scheduled(cron = "0/5 * * * * ?")
void print(){
System.out.println("+----+--------+");
}
}
task:
scheduling:
pool:
size: 10 #线程池数量,默认只为1。
shutdown:
await-termination: false #关闭时是否等待所有完成
await-termination-period: 10s #最大等待时间
@Scheduled(cron = "0/${a.b.c:10} * * * * ?")
简介:
简单编写思想
调整的时间顺序,思维应该顺着从小到大
编写规则
秒数:
纯数字系列:
基于系统时间,比如 5即代表当系统时间走到某分钟05秒时触发。
每分钟0秒触发格式为 0 * * * * ? 或者 0 0/1 * * * ? 。
最后的问号代表什么:
其实最后一位代表星期几。为避免与前面冲突,故使用 ? 来表示任意。
简介:
分布式监控程序,非 SpringBoot官方开发,使用时需导入与之对应的官方版本号,否则报错。
注意事项:
子节点要开放什么内容全部由子节点规定,Server无权干涉。(安全性)
实现流程:
导包 admin + SpringBoot Web
yml配置主从客户端
配置Server,主程序上开启 @EnableAdminServer注解, yml中配置端口。
配置Client,yml中配置主服务器即可。
简单实现
配置 Server:
server:
port: 80
@EnableAdminServer
配置 Client:
server:
port: 8080
spring:
boot:
admin:
client:
url: http://localhost #server路径地址
management:
endpoints:
web:
exposure:
include: "*" #开放所有,即13个端点
endpoint:
health:
show-details: always #展示细节,true。默认false
界面预览
info信息配置
# yml文件中添加以下配置
management:
info:
env:
enabled: true #使能够info
info:
author: ThinkStu
des: "good program" #具体信息,纯手工编写yml
123456789
@Component
public class AppinfoContributor implements InfoContributor {
@Override
public void contribute(Info.Builder builder) {
builder.withDetail("msg","good");
}
}
自定义Health健康状况
比如 client程序中存在 Redis,那么就会显示redis的健康状况。
四种状态:
up在线、down离线、unkown未知、outofservice失去服务。
我们可以利用四种状态在编码中写一些自定义程序,然后为这些程序添加 health监控。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yX3TLkw1-1651739102964)(https://tva1.sinaimg.cn/large/e6c9d24egy1h1o6xhkv8sj21xs0u0tcc.jpg)]
@Component
public class HealthConfig extends AbstractHealthIndicator {
@Override
protected void doHealthCheck(Health.Builder builder){
boolean check=true;
if (check){
builder.withDetail("runtime","xxx");
builder.status(Status.UP);
}else{
builder.withDetail("error","系统运行失败");
builder.status(Status.DOWN);
}
}
}
结合邮件系统:邮件信息报警系统
JMS消息模型
JMS消息种类
TextMessage、MapMessage、ByteMessage、StreamMessage、ObjectMessage、Message
实现JMS的技术
ActiveMQ、Redis、RabbitMQ、RocketMQ(没有完全实现)
优点:
具有跨平台性,服务器、供应商、生产者消费者可以使用不同的语言来实现。
AMQP消息模型:
direct exchange、fanout exchange、topic exchange、headers exchange、system exchange
AMQP消息种类:byte[ ]
AMQP实现:
RabbitMQ、RockerMQ、StormMQ等
四种消息中间件简介
ActiveMQ:Apache产品,社区已经不活跃。
RabbitMQ:使用频率较高,速度中等,数据直接写在磁盘中,不易丢失。
RocketMQ:阿里巴巴开源的消息中间件,Java语言开发,各方面也表现的比较优越,几乎同时解决了Kafka和RabbitMQ它们两个的缺点,速度介于两者之间,数据不易丢失。
Kafka:速度快,但数据写在内存中、易丢失。
实现暂略。
简介:
resources/static
中创建 error目录,然后导入错误展示页面。原理:
当触发错误页面时,BasicErrorController类被调用。(其将会返回 JSON或 html格式的错误数据,具体由用户请求方式而定)
获取错误的静态页面,置于 /resource/static/error 目录中。
两种形式:
xx形式 与 具体的数字形式。4xx.html、5xx.html的优先级低于具体的数字权限,如404、503等,所以它们是可以同时的存在的。
@Component
public class MyException extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
Map<String ,Object> map=super.getErrorAttributes(webRequest, options);
map.remove("error");
map.put("msg","错误请求");
return map;
}
}
@Slf4j
@RestController
@RequestMapping("/users")
public class UsersController {
@GetMapping()
String getById(HttpServletResponse response) throws IOException {
log.error("fashion");
return "啊啊啊啊";
}
}
Logger log= LoggerFactory.getLogger(UsersController.class);
**从左至右:**日志记录时间、级别、PID、所属线程、类对象、信息。
简介
位置说明
SpringBoot默认会过滤所有的静态资源,一共有5个位置。
开发者可以将静态资源放在这5个位置中的任意一个,优先级依次降低。
classpath:/META-INF/resource/
classpath:/resource/
classpath:/static/
classpath:/public/
/
如果将文件夹中存在同名文件,则只有第一个会生效。
简介
正常情况,如果我们有静态网页会放在/static
里,然后访问的时候需要添加 .html后缀。如果不想添加.html后缀,则需要在 Controller中加一层转发的操作。
但是我们有更简单的方法,而且节省资源。
效果:
访问 http://localhost/aaa
相当于 http://localhost/aaa.html
简单实现:
首先将文件置于/static
下。
然后编写 @Configuration、配置 WebMvcConfigurer接口,实现跳转。
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/uuu").setViewName("/uuu.html");
registry.addViewController("/ooo").setViewName("/ooo.html");
}
}
简介:
在服务器中使用日志。
在正式业务上线后不能使用开发工具进行调试,我们需要日志系统。
说明:
保存到服务器上的日志数据,我们可以使用 IDEA打开(拥有格式)。
简单使用
logging:
file:
max-history: 10
max-size: 10MB
name: server.log
pattern:
rolling-file-name: server.%d{yyyy-MM-dd}.%i.log
简介:
SpringBoot约定在不同环境下配置文件的名称规则为
profile占位符表示当前环境的名称。
作用:
解决在多环境开发下配置文件混乱的问题。
版本限制说明:
简单实现
简介:
有一些特殊任务需要在系统启动时执行(例如配置文件加载、数据库初始化等),SpringBoot对此提供了两种基本一样的方案:CommandLineRunner类、ApplicationRunner类。
两种简单实现:
CommandLineRunner:Spring Boot 项目在启动时会遍历所有 CommandLineRunner的实现类,并调用其中的 run 方法,如果整个系统中有多个 CommandLineRunner 的实现类,那么可以使用 @Order注解对这些实现类的调用顺序进行排序。Order值越小越优先执行,可为负数,负数最小。
@Component
@Order(-100)
public class StartPrint implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("优先启动~");
}
}
ApplicationRunner:几乎同上。两者 Order通用,计算执行顺序的时候需要同时参考两者。
@Component
@Order(-1000)
public class Start03 implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("33333");
}
}
简介:
异常,指的是当正常访问时服务器时发生的异常,并非指 404之类的异常。
简单实现
( utils包下的异常处理类)
// 拦截所有异常
@RestControllerAdvice
public class ProjectExceptionAdvice {
@ExceptionHandler(Exception.class)
R allException(Exception ex) {
ex.printStackTrace();
return new R("服务器发生未知故障,请稍后重试...");
}
}
简介:
在 yml中配置当前日志的打印等级,一共有两种形式。
简单实现:
按包名划分
logging:
level:
root: error # root是根路径 / 的正式写法
com.test.controller: info
分组划分,先分组再划定等级。
logging:
group:
ebank_name: com.test.controller,com.test.mapper
level:
root: error
ebank: info
简介:
有时候我们需要改写一些比较老的程序,或者作 xml文件配置。
虽然 SpringBoot不推荐使用 xml进行配置,但是如果开发者需要使用 xml配置,那么只需在 resources目录下提供配置文件、然后在主程序上导入即可。
说明:
简介:
yml 中编写了众多属性,那么该入伙获取呢?
获取方式分类:
单个读取:@Value注解
@Value("${users[0].name}")
String name;
@Value("${a.b.c:10}") // 读取不到则加载默认值
String num;
@Autowired
Environment env;
@Test
void contextLoads() {
env.getProperty("users[0].name");
}
选择读取:既可以为 Spring原生 Bean注入属性,也可以为第三方 Bean注入属性。
实现步骤:
yml存在数据
创建属性获取 Bean( @Component + @Data + @ConfigurationProperties 注解)。
在这一步 Spring可能会提示缺少相应包,按提示导入即可。
注入该 Bean并使用
@Data
@Component
@ConfigurationProperties("users2")
public class UsersConfiguration {
String name;
String age;
}
// 使用
@Autowired
UsersConfiguration userConfig;
简介:
我怀疑此种方式存在Bug,单级可以识别,一旦遇到多级就不能识别我的文件。还应该注意的是,方法不止这一种,但这种比较直接。
简单实现:
@PropertySource属性引入第三方文件(得加上类全路径名)
@Data
@Configuration
@PropertySource(value = "classpath:users.yml")
public class CustomConfig {
@Value("${users}")
Object name;
}
所有的拦截器都必须实现 HandlerInterceptor接口。
**拦截器( Interceptor)**同 Filter 过滤器一样,都是面向切面编程 AOP 的具体实现。
在这一步才能配置拦截的路径,还可以配置排除的路径 excludePathPatterns。
原理:利用 ModelAndView对象。
@GetMapping
ModelAndView get() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("/uuu.html");
return modelAndView;
}
在 xml或者 yml文件中进行配置时,可以使用全路径名缩写形式:classpath:
classpath:UserMapper.class
# 相当于全路径+UserMapper.class
简单的页面重定向,页面跳转与重定向并不一样。
@GetMapping()
String getById(HttpServletResponse response) throws IOException {
response.sendRedirect("/cancel.html");
return null;
}
我是实在想不到,竟然还会有表格画法这种教程。
节点用+号码表示,线条用-号表示,空格表示表中的待填项。
System.out.println("+----+--------+");
System.out.println("+ | |");
System.out.println("+ | |");
System.out.println("+----+--------+");
dollar + 大括号
username: kk
your_name: ${username}
为什么能够实现?
理解 SpringBoot底层工作源码,采取官方接口 ___Aware。
简单实现:
只要继承 ApplicationContextAware并实现 set方法即可。
public class Demo01 implements ApplicationContextAware {
ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
}
简介
favicon,网站图标。
虽然在 html代码中也可以添加,不过在此添加较为方便。
简单实现
/resource/static/
下。问题简介:
SpringBoot程序在打包的时候会默认先执行测试类 Test里面的方法。
这是因为存在 Maven生命周期,后执行的必须先执行前面的所有内容。
解决:maven设置跳过测试
简介:
手动排除 SpringBoot的自动配置。
两种实现方法:
简介:
查看在 pom文件中导入的具体软件版本(全部)。
可以分为两种,Spring官方 与 阿里云镜像 所创建的 SpringBoot程序并不一样。
Spring官方
两层点击:spring-boot-starter-parent — spring-boot-dependencies
阿里云
在 dependencyManagement下的与中,点击查看。
简介:
有利于项目与项目之间的解耦合,促进开发。
操作流程:
简介:
在没有网络的计算机上创建 SpringBoot程序,过程离线。
但事先需要在官网上把相应文件创建并下载。
步骤:
简介:
制作模板程序,可以在学习的过程中大量复制某份程序。
制作模板步骤:
选择模板
删除项目结构的无用文件
删除pom文件两行、改一行(结束)
使用步骤:
通常都是在项目中直接将上面的模板当成组件module导入。
简介:
排除 Tomcat依赖,可以换成其他任意服务器程序。
步骤:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-tomcatartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jettyartifactId>
dependency>
简介:
修改控制台打印出来的 Banner广告位。
两种方法:
#关闭banner
spring:
main:
banner-mode: off
#修改banner为指定图片
spring:
banner:
image:
location: WechatIMG96.jpeg
简介:
我们在执行测试的时候,SpringBoot默认不开启服务器、节省资源。但是现在由于业务需求,需要对其测试,采用 WebEnvironment Web环境。
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class Test03 {
@Test
void test03(){
}
}
webEnviroment参数说明:
简介:
在测试中经常会有写入数据库操作,但我只想知道是否执行成功,不想污染数据库。
步骤:
@SpringBootTest
@Transactional
public class Test04 {
@Test
void test04(){
}
}
简介:
想要在测试用例中添加一些临时属性,在 @SpringBootTest 中使用参数属性注入即可。
@SpringBootTest(properties = {"a=b","server.port=99999"})
public class Test02 {
@Value("${a}")
String msg1;
@Value("${server.port}")
String msg2;
@Test
void test02( ){
System.out.println(msg1);
System.out.println(msg2);
}
}
简介:
使用 Jackson作为项目的序列化工具时,可以作用在属性、方法或者类上面,用来规避不想要的序列化功能。
@JsonIgnore
private String username;
简介:
我们在 SpringBoot项目中能够打包是因为配置了 maven插件,该插件由 SpringBoot parent 中提供。但是其他公司可能不采用 SpringBoot parent 作为parent,此时就需要配置。
示意图:避免重复打包
简介:
隐藏不想看见的文件,避免冗余。
set up — Edit — File Type.
注意事项
在 IDEA 2022.01版本中,我遭遇了隐藏文件时产生的 Bug,需注意。
简介:
JDK8 提供了两个单位类,用来规范单位的表达形式。
分别为:
//使用
1. Duration duration1=Duration.of(3, ChronoUnit.HOURS);
2. Duration duration2=Duration.ofHours(3);
3. @DurationUnit(ChronoUnit.HOURS)
Duration duration3;
//DataSize同理,例如:
DataSize dataSize=DataSize.ofGigabytes(2);
修改配置文件名,然后在程序运行时再指定配置文件名
虽然感觉这种方式比较愚蠢,但是暂时收录
maven是比 Spring更底层的存在,Spring建立在 maven的基础之上。
我们可以使用 maven来控制并改变 Spring运行的时的 yml文件配置。
优势阐述:
Mybatis之类是基于JDBC开发的,可以说 jdbc是更加底层的存在。
安全性与底层效率要较其他框架高,银行相关行业比较热衷此。
步骤:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
@Autowired
JdbcTemplate jdbcTemplate;
说明:
开启流程:到pom包、idea设置中开启。
<dependency>
<groupId>javax.validationgroupId>
<artifactId>validation-apiartifactId>
<version>2.0.1.Finalversion>
dependency>
<dependency>
<groupId>org.hibernate.validatorgroupId>
<artifactId>hibernate-validatorartifactId>
<version>8.0.0.Alpha3version>
dependency>
有时候我们需要在代码中编写测试用例,而不使用 postman这类工具。
get请求访问页面,先开启webEnviroment、AutoConfigureMockMVC,然后注入MOckMVC,最后执行操作
只是想在测试的时候加载一些随机数据,应该把以下内容用Profile思想来编写:即多份yml文件。
random
testData:
name: ${random.uuid}
age: ${random.int(6,100)}
id: ${random.value} #MD5加密,32位
@Data
@Component
@ConfigurationProperties( "testdata")
public class TestDataConfig {
String name;
Integer age;
String id;
}
此章节需要日积月累。
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/adult?serverTimezone=UTC
username: root
password: "$Now2022"
123456
@Mapper
public interface UsersMapper {
@Select("select * from users where id = #{id}")
List> getById(Integer id);
}
12345
@Autowired
UsersMapper mapper;
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
@Mapper
public interface UsersMapper extends BaseMapper<Users> {
@Select("select * from users;")
List<Users> getAll();
}
12345
public class UsersServiceImpl extends ServiceImpl<UsersMapper,Users> implements UsersService , IService<Users> { }
1
mybatis-plus:
global-config:
db-config:
id-type: auto
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/adult?serverTimezone=UTC
username: root
password: "$Now2022"
一门登录技术, 学会不易。
Spring Security是基于内存级别的认证,不是数据库。
SpringBoot为 SpringSecurity提供了很好的支持。
导包之后,SpringSecurity为我们提供了一个默认页面登录页面(未登录时拦截了所有的请求!),默认账号为user,密码见控制台。如果对初始的账号密码不满意,可以在yml中修改。
spring:
security:
user:
name: admin
password: admin
roles: ADMIN #此处是区分大小写的,需特别注意
导包
yml简单配置
代码中正式配置
配置说明:
访问/admin/**
需要 ADMIN角色权限
访问/user/ **
需要 CAT或者 USER角色权限。
访问其他任意资源都要先登录。
默认登录页面是 /login。
permitAll作用于 /login ,表示和登录相关的接口都不需要认证即可访问。
csrf( ).disable( )表示关闭 csrf,防止服务器被 csrf攻击。
(csrf攻击:Cross Site Request Forgery,跨站请求伪造。)
@Configuration
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**")
.hasRole("ADMIN")
.antMatchers("/user/**")
.access("hasAnyRole('CAT','USER')")
.anyRequest().authenticated()
.and().formLogin()
.loginProcessingUrl("/login")
.permitAll().and().csrf().disable();
}
}
.and().httpBasic()
简介:
目前为止我们使用的还都是 Spring Security默认提供的登录页面。
在前后端分离的开发中,我们需要自定义登录页面与返回的 JSON格式数据
思想:
/login_new
,但是最终的数据提交地址还是/login
。简单实现(配置):
.and()
.formLogin()
.loginPage("/login_page")
.loginProcessingUrl("/login")
.usernameParameter("name")
.passwordParameter("pass")
.successHandler((req, resp, auth) -> {
Object principal = auth.getPrincipal();
System.out.println(principal + "-------principle"); resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
Map<String, Object> map = new HashMap<>(16);
map.put("status", "200");
map.put("msg", principal);
ObjectMapper om = new ObjectMapper();
writer.write(om.writeValueAsString(map));
writer.flush();
writer.close();
})
.failureHandler((req, resp, exception) -> { resp.setContentType("application/json;charset=utf-8");
PrintWriter writer = resp.getWriter();
resp.setStatus(401);
Map<String, Object> map = new HashMap<>(16);
if (exception instanceof LockedException){
map.put("msg","账户冻结");
}else if (exception instanceof BadCredentialsException){
map.put("msg","账号密码错误,请重新输入");
}else {
map.put("msg","登录失败");
}
ObjectMapper om = new ObjectMapper();
writer.write(om.writeValueAsString(map));
writer.flush();
writer.close();
})
.permitAll()
.and()
.csrf()
.disable();
简介:
默认访问 /logout
即可注销。
但是在这里我遇到问题,可能是这种方式已经失效。
.and()
.logout()
.logoutUrl("/logout")
.clearAuthentication(true)
.invalidateHttpSession(true)
.addLogoutHandler((req, resp, authentication) -> {
})
.logoutSuccessHandler((req, resp, authentication) -> {
try {
resp.sendRedirect("/login_page");
} catch (IOException e) {
e.printStackTrace();
}
})
简介:
所谓加盐就是一种加密形式,其既可以是随机数、也可以是用户名。
加盐之后原本密码相同的用户所生成的最终密码也不会相同,可以有效防止跑库破解密码。
传统加盐方式:需要在数据库中记录用户的盐值。
Spring Security加盐:
Spring Security提供了多种加盐方案。
官方推荐使用BCryptPasswordEncoder,其使用了 BCrypt 强哈希函数,开发者在使用时可以选择提供 strength 和 SecureRandom 实例 ,strengh越大,密钥的迭代次数越多,迭代次数为2的strength次方。(strength 取值在4~31 之间,默认为 10)
@Configuration
public class PasswordEncoderConfig {
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder(10);
}
}
简单使用:
简介:
将 Spring Security基于内存级别的登录验证信息存储到数据库。
遗憾:暂时未能成功实现。
实现步骤:
建表语句范例:
drop table if exists user;
drop table if exists role;
drop table if exists user_role;
create table user(
id int primary key auto_increment,
username varchar(32),
password varbinary(255),
enabled tinyint(1),
locker tinyint(1)
);
create table role(
id int,
name varchar(32),
nameZh varchar(32)
);
create table user_role(
id int(11),
uid int(11),
rid int(11)
)
简介:
本节基于 OAuth2框架,该框架的使用与实现账号密码登录不冲突。
遗憾:暂时未能成功实现。
令牌技术说明:
令牌技术的优势在于可以只授权部分权限给第三方,从而避免了密码直接泄露的可能性。第三方拿着令牌可以访问一些基础资源,如:头像、用户名等。很多第三方也只支持 token而不支持 Cookie(如:微信小程序)。
交互流程(三次):
OAuth授权模式说明:
OAuth具有多种授权模式,其各有千秋、按需选择。
简介:
一种可以将 代码编写 和 需求文档编写 融为一体的技术(暂时无该需要)。
简单实现