笔记
Maven项目:
- 从官网复制一份pom.xml
- 更改 maven mirror :
- ~/.m2.setting.xml 影响全局
- pom.xml 仅影响当前项目
- 按着官方文档创建一个Controller,一个Application
- 运行,成功。
依赖注入
Springboot推荐注解:官方文档
Spring Boot favors Java-based configuration. Although it is possible to use SpringApplication with XML sources, we generally recommend that your primary source be a single @Configuration class. Usually the class that defines the main method is a good candidate as the primary @Configuration.
1. 从XML配置加载Bean
创建 src/main/resources/applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- <context:component-scan base-package="com.in28minutes.spring.basics"/> -->
<bean id="" class=""></bean>
</beans>
创建 configuration/XmlConfiguration.java
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource({"classpath*:applicationContext.xml"})
public class XmlConfiguration {
}
这样就大功告成了。但是xml方式是个古老的方式。。
2. 从Java配置加载Bean
创建 configuration/JavaConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JavaConfiguration {
@Bean
public String someDummyBean1() {
return "someDummyBean1";
}
}
3. 自动装配
@Inject注解,需要引入javax.inject
一个小知识,记下来。转载于: @Autowired,@Inject,@Resource的区别:
1、@Autowired是spring自带的,@Inject是JSR330规范实现的
2、@Autowired、@Inject用法基本一样,不同的是@Autowired有一个request属性
连接数据库
Docker:-> MySQL
ORM:Object Relationship Mapping 对象关系映射 -> MyBatis
JPA:一个不需要写SQL的ORM框架?打个笔记,有时间专门看看。。。
参考的官方文档:mybatis-spring-boot-autoconfigure
创建 mapper/CityMapper.java
@Mapper
public interface CityMapper {
@Select("SELECT * FROM CITY WHERE state = #{state}")
City findByState(@Param("state") String state);
}
然后通过构造器注入mapper,但是发现还需要一个DataSource。
所以: 参考官方文档:Working with SQL Databases
MVC
Model View Controller
開始根據前端接口写模块
吭哧吭哧。。。。
security -> Springboot:Securing a Web Application
官方文档:保护Web应用程序
本指南将引导您完成使用受Spring Security保护的资源创建简单的Web应用程序的过程。
引入 pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
在configuration包里创建一个类:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
现在所有请求都被拦截了。
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
}
这样又能访问了,但是有些还是不能。。。
Request URL: http://...
Request Method: POST
Status Code: 403
查了一些资料。然后发现了一个叫csrf的东西。
http.csrf().disable();
这时候就可以访问了。
Springboot antMatchers:
匹配url遵循如下规则:
? matches one character(匹配一个字符)
* matches zero or more characters(匹配0个或多个字符)
** matches zero or more directories in a path(匹配0个或多个目录)
{spring:[a-z]+}} matches the regexp [a-z]+ as a path variable named "spring",意思是将使用[a-z]+ 正则去匹配spring的变量值
继续加入:
@Bean
@Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
这里发现withDefaultPasswordEncoder() 方法被废弃掉了。看了源代码的注释看到它是不安全的。
Using this method is not considered safe for production, but is acceptable for demos and getting started.
Auth:
- Authentication:鉴权。-> 是不是?
- Authorization:验权。-> 有没有权限?
登陆状态维持
Cookie:
Cookie 是一些数据, 存储于你电脑上的文本文件中。
当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息。
Cookie 的作用就是用于解决 "如何记录客户端的用户信息"
参考文档:JavaScript Cookie | 菜鸟教程
记录一个权威的文档:rfc cookie
SecurityContextHolder.getContext()
// 把用户信息(Cookie)保存在一个地方
登陆 / 注册
pass
查看约束信息:show create table #{表名};
登出(logout)
参考1: spring-security-logout
参考2: docs.spring.io/spring-security
测试
- 自动化测试
- maven-surefire-plugin 单元测试
- maven-failsafe-plugin 集成测试
JUnit 5 User Guide
Mockito and JUnit 5 – Using ExtendWith
- 持续集成(CI):频繁地将代码集成到主干
exec-maven-plugin
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>start-test-database</id>
<phase>pre-integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<longModulepath>false</longModulepath>
<executable>docker</executable>
<arguments>
<argument>run</argument>
<argument>--name</argument>
<argument>test-mysql</argument>
<argument>-e</argument>
<argument>MYSQL_ROOT_PASSWORD=123456</argument>
<argument>-e</argument>
<argument>MYSQL_DATABASE=springboot</argument>
<argument>-p</argument>
<argument>3307:3306</argument>
<argument>-d</argument>
<argument>mysql</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>teardown-test-database</id>
<phase>post-integration-test</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<longModulepath>false</longModulepath>
<executable>docker</executable>
<arguments>
<argument>rm</argument>
<argument>-f</argument>
<argument>test-mysql</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
集成测试 和 销毁测试数据库
运行:>mvn pre-integration-test
销毁:>mvn post-integration-test
Jenkins
docker run -p 8080:8080 -v E:docker:/var/jenkins_home jenkins
补剩下的笔记。。。
- Controller 参数验证,清洗
- Service 处理业务需求
- Dao 访问数据库
MyBatis参考文档
MyBatis Getting Started
记录问题
遇到前端数据传不过来的问题:
正确返回的response:{"status":"ok","msg":"登陆成功","data":{"id":1,"name":"张三","avatar":"","createdAt":"2020-02-19T05:35:34.331Z","updatedAt":"2020-02-19T05:35:34.331Z"},"login":true}
错误返回的response:{"status":"ok","msg":"登陆成功","login":true}
解决方法:data的getter忘了写。
登陆时返回404
返回的response:{"timestamp":"2020-02-19T05:39:22.740+0000","status":404,"error":"Not Found","message":"No message available","path":"/auth/login"}
解决方法:给方法加上@ResponseBody
使用错误的账号登陆时返回403
返回的response:{"timestamp":"2020-02-19T05:41:18.728+0000","status":403,"error":"Forbidden","message":"Access Denied","path":"/auth/login"}
正确返回的response:{"status":"fail","msg":"用户不存在","data":null,"login":false}
解决方法:UserDetailsService接口抛出UsernameNotFoundException。
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
解决方法:使用 org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
绝对不可以使用明文密码。
-
- 必须加密
-
- 加密是不可逆的
-
- 加密必须是一致的
WARNING:不要自己设计加密算法
created_at和updated_at两个字段不断的刷新,并且和数据库对不上
原因:驼峰形式和下划线形式匹配不上
解决方法:application.properties 加上 mybatis.configuration.mapUnderscoreToCamelCase=true
Bean循环依赖问题
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| webSecurityConfig defined in file [.../WebSecurityConfig.class]
↑ ↓
| userService defined in file [.../UserService.class]
└─────┘
解决方法:我这里把一个Bean变成字段注入。。。了。。。
避免某些字段序列化到前端(例如:密码)
解决方法:Spring默认的序列化工具是jackson。查了资料:jackson not serelize得知@JsonIgnore注解可以解决
maven-surefire-plugin报告 Tests run:0, Failure:0, Error:0, Skipped:0
相关:Gradle 5 JUnit BOM and Spring Boot Incorrect Versions
解决方式:pom.xml添加
<properties>
<junit-jupiter.version>5.6.0</junit-jupiter.version>
</properties>
集成测试:A type incompatibility occurred while executing org.codehaus.mojo:exec-maven-plugin:1.6.0:exec: java.lang.String cannot be cast to org.codehaus.mojo.exec.Modulepath
解决方法:
<longModulepath>false</longModulepath>
重构
DRY原则:Don’t Repeat Yourself
解决:重构了部分重复代码。。。(写了一个静态工厂方法)
自动化测试
测试驱动开发 TDD:Test-Driven Development
为什么?
- 自动
- 节省时间
- 人会犯错
- 测试水平
单元测试:unit test
用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作
- 黑盒测试
集成测试:intergration test
将部分代码集成一块进行测试
冒烟测试:smoke test
测试软件的基本功能
回归测试:regression test
重复以前的全部或部分的相同测试