很早之前写过Thymeleaf的文章,所以重新温习一下,非前后端分离,仅仅只是学习
- 官网: https://www.thymeleaf.org/
SpringBoot可以快速生成Spring应用,简化配置,自动装配,开箱即用。
JavaConfiguration
java类来代替XML的配置。对常用的第三方库提供了配置方案,可以很容易的与Spring进行整合,快速进行企业级开发。
优势:不需要配置任何XML文件、内嵌tomcat、默认支持JSON,不需要进行转换、支持RESTful。
使用时:启动类必须覆盖所有与业务相关的类,即启动类所在的包必须是业务类所在包的同包或者⽗包,如果没有覆盖,业务类就不会⾃动装配到IoC容器中。
YAML是不同于Properties的另外⼀种⽂件格式,同样可以⽤来写配置⽂件,Spring Boot默认⽀持YAML格式,
YAML的优点在于编写简单,结构清晰,利⽤缩紧的形式来表示层级关系。
相⽐于Properties,YAML可以进⼀步简化配置⽂件的编写,更加⽅便。属性名和属性值之间必须⾄少⼀个空格。
如果Properties和YAML两种类型的⽂件同时存在,Properties的优先级更⾼。
配置⽂件除了可以放置在resources路径下之外,还有3个地⽅可以放置,优先级顺序如下所示:
1、根路径下的config中的配置⽂件
2、根路径下的配置⽂件
3、resources路径下的config中的配置⽂件
4、resources路径下的配置⽂件
可以直接在Handler中读取YAML⽂件中的数据,⽐如在业务⽅法中向客户端返回当前服务的端⼝信息。
@Value("${server.port}")
private String port;
JSP:动态网页技术,底层为Servlet,可在html代码中编写Java代码
JSP底层原理:它是一种中间层组件,开发者可以在这个组件中将java代码与html代码整合,由JSP引擎将组件转为Servlet,再把混合代码翻译为Servlet的响应语句,输出给客户端。
环境搭建
1、创建基于Maven的Web项⽬,pom.xml
<!-- Spring项目转为SpringBoot-->
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.3.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入Spring Boot 内嵌的Tomcat对jsp的解析包-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>9.0.33</version>
<!--报错 <version>7.0.59</version>-->
<scope>provided</scope>
</dependency>
<!-- servlet 依赖的jar包start-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.3</version>
<scope>provided</scope>
</dependency>
<!-- jsp 依赖的jar包start-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- jstl标签 依赖的jar包start-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
</dependencies>
2、创建Handler
@Controller
@RequestMapping("/hello")
public class HelloHandler {
@GetMapping("/index")
public ModelAndView index(){
ModelAndView modelAndView = new ModelAndView("index");
modelAndView.addObject("msg","hello springboot jsp");
return modelAndView;
}
}
3、JSP
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page isELIgnored="false" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>${msg}</h2>
</body>
</html>
4、application.yml(配置视图解析器)
server:
port: 8080
#springmvc视图解析器
spring:
mvc:
view:
prefix: /
suffix: .jsp
5、编写启动类Application.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
6、更新web.xml,防止加载其他xml片段的时候包报错
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Archetype Created Web Application</display-name>
</web-app>
实际运用(crud)
1、pom.xml导入jstl依赖
报错: NoSuchMethodError: org.apache.tomcat.JarScanner.scan
,只需要在Dependencies下找到自己引入的tomcat,比如我自己引入的是7.0.59,展开后下面9.0.33是springboot自带的,将版本改为9.0.33就可以了,问题解决!
2、实体类User:id和name
3、Handler中创建业务⽅法,返回User对象
@Controller
@RequestMapping("/user")
public class UserHandler {
@Autowired
private UserService userService;
@GetMapping("/findAll")
public ModelAndView findAll(){
// User user1 = new User(1, "jack");
// User user2 = new User(2, "jack2");
// List userList = Arrays.asList(user1, user2);
ModelAndView modelAndView = new ModelAndView("findAll");
modelAndView.addObject("userList",userService.findAll());
return modelAndView;
}
@PostMapping("/save")
public String save(User user){ //写一个save页面form
userService.save(user);
return "redirect:/user/findAll";
}
@GetMapping("/deleteById/{id}")
public String deleteById(@PathVariable("id") Integer id){
userService.deleteById(id);
return "redirect:/user/findAll";
}
@GetMapping("/findById/{id}")
public ModelAndView findById(@PathVariable("id") Integer id){
ModelAndView modelAndView = new ModelAndView("update");
modelAndView.addObject("user",userService.findById(id));
return modelAndView;
}
@PostMapping("/update")
public String update(User user){
//写一个update页面form,但先要根据id查询数据,在修改
userService.update(user);
return "redirect:/user/findAll";
}
}
4、Repository
public interface UserService {
public Collection findAll();
public User findById(Integer id);
public void save(User user);
public void deleteById(Integer id);
public void update(User user);
}
5、Service
@Repository
public class UserRepositoryImpl implements UserRepository {
public static Map map;
static {
map = new HashMap<>();
map.put(1,new User(1,"jack1"));
map.put(2,new User(2,"jack2"));
map.put(3,new User(3,"jack3"));
}
@Override
public Collection findAll() {
return map.values();
}
@Override
public User findById(Integer id) {
return map.get(id);
}
@Override
public void save(User user) {
map.put(user.getId(),user);
}
@Override
public void deleteById(Integer id) {
map.remove(id);
}
@Override
public void update(User user) {
map.put(user.getId(),user);
}
}
6、JSP
findAll.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ page isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<table>
<tr>
<th>编号</th>
<th>姓名</th>
<th>操作</th>
</tr>
<c:forEach items="${userList}" var="users">
<tr>
<td>${users.id}</td>
<td>${users.name}</td>
<td>
<a href="/user/deleteById/${users.id}">删除</a>
<a href="/user/findById/${users.id}">修改</a>
</td>
</tr>
</c:forEach>
</table>
</body>
</html>
save.jsp
<form action="/user/save" method="post">
<input type="text" name="id" />
<input type="text" name="name" />
<input type="submit" value="保存" />
</form>
update.jsp
<form action="/user/update" method="post">
<input type="text" name="id" value="${user.id}" readonly />
<input type="text" name="name" value="${user.name}" />
<input type="submit" value="修改" />
</form>
Thymeleaf是⽬前较为流⾏的视图层技术,Spring Boot官⽅推荐使⽤Thymeleaf。
它可以实现前后端分离的交互方式,即视图与业务数据分开响应,还可以直接将服务端返回的数据生成为HTML文件,同时也可以处理XML、JavaScript、CSS等格式。
Thymeleaf最大的特点是既可以直接在浏览器打开(静态方法),也可以结合服务端,将业务数据填充到html后,动态生成的页面(动态方法)???
1 使用
1、创建Maven⼯程,不需要创建Web⼯程,pom.xml
spring-boot-starter-parent
org.springframework.boot
2.3.4.RELEASE
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-thymeleaf
2、application.yml
classpath:一般用来指代"src/main/resources"下的资源路径,其本质其实是指项目打包后target的classes下的路径
spring:
thymeleaf:
prefix: classpath:/templates/ #模板路径
suffix: .html #模板后缀
servlet:
content-type: text/html #设置content-type
encoding: utf-8 #编码格式
mode: HTML5 #校验h5格式
cache: false #关闭缓存(在开发过程中可以立即看到修改后的结果)
3、创建Handler
@Controller
@RequestMapping("/hello")
public class HelloHandler {
@GetMapping("/index")
public ModelAndView index(){
ModelAndView modelAndView = new ModelAndView("index");
modelAndView.addObject("name","小明");
return modelAndView;
}
}
4、启动类
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
5、templates目录下编写HTML
<!DOCTYPE html>
<html lang="en">
<!--引入标签-->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--name的值会覆盖hello-->
<p th:text="${name}">hello</p>
</body>
</html>
2 注意
如果需要加载后台返回的业务数据,则需要在HTML⻚⾯中使⽤Thymeleaf模版标签来完成。
1、需要引⼊模版标签 <html xmlns:th="http://www.thymeleaf.org"></html>
2、通过特定的标签完成操作 <p th:text="${name}">hello</p>
Thymeleaf模版标签不同于JSTL,Thymeleaf模版标签是直接嵌⼊到HTML原⽣标签内部。
3 Thymeleaf常⽤标签【重点】
th:text
用于文本的显示,将业务数据的值填充到html标签中。
th:if
用于条件判断,对业务数据的值进行判断。成立,则显示内容。
<p th:if="${score>=90}">优秀</p>
<p th:if="${score<90}">不优秀</p>
th:unless
也⽤作条件判断,逻辑与th:if恰好相反,如果条件不成⽴则显示,否则不显示。
th:switch th:case
两个结合起来使⽤,⽤作多条件等值判断,
<div th:switch="${id}">
<p th:case="1">a</p>
<p th:case="2">b</p>
<p th:case="3">c</p>
</div>
th:action
⽤来指定请求的URL,相当于form表单中的action属性、【重点】
如果action的值直接写在HTML中,则需要使⽤@{},
<form th:action="@{/hello/login}" method="post">
<input type="submit"/></form>
如果是从后台传来的数据,则使⽤${}。
@GetMapping("/redirect/{url}")
public Stringredirect(@PathVariable("url") String url, Model model){
model.addAttribute("url","/hello/login");
return url;
}
<form th:action="${url}" method="post">
<input type="submit"/></form>
th:each
⽤来 遍历集合(类似foreach)
<table>
<tr th:each="user:${userList}">
<td th:text="${user.id}"></td>
<td th:text="${user.name}"></td>
</tr>
</table>
th:value
⽤来给标签赋值
<input type="text" th:value="${idValue}"/>
th:src
⽤来引⼊静态资源,相当于HTML原⽣标签img、script的src属性。
<img th:src="${src}"/>
如果src的值直接写在HTML中: <img th:src="@{/1.png}">
th:href
⽤作设置超链接的href
List<User> list = Arrays.asList(new User(1,"jack"),new User(2,"tom"));
ModelAndView modelAndView = new ModelAndView("index");
modelAndView.addObject("list",list);
modelAndView.addObject("userName","tom");
<select>
<option th:each="user:${list}"
th:value="${user.id}"
th:text="${user.name}"
th:selected="${user.name == userName}">
</option>
</select>
结合th:each来使⽤,⾸先 遍历list集合 动态创建option元素,根据每次遍历出的user.name与业务数据中的userName是否相等来决定是否要选择。
th:attr
给HTML标签的任意属性赋值
<input th:attr="value=${attr}"/>
等价于
<input th:value="${attr}"/>
4 Thymeleaf对象
Thymeleaf支持访问Servlet Web的原生资源,HttpServletRequest、HttpServletResponse、HttpSession、ServletContext。
- request:获取HttpServletRequest对象
- response:获取HttpServletResponse对象
- session:获取HttpSession对象
- *servletContext:获取ServletContext对象
@GetMapping("/servlet")
public String servlet(HttpServletRequest request){
request.setAttribute("value","request");
request.getSession().setAttribute("value","session");
request.getServletContext().setAttribute("value","servletContext");
return "servletTest";
}
<p th:text="${#request.getAttribute('value')}"></p>
<p th:text="${#session.getAttribute('value')}"></p>
<p th:text="${#servletContext.getAttribute('value')}"></p>
<p th:text="${#response}"></p>
[注意]Thymeleaf⽀持直接访问session, ${#request.getAttribute('name')}
也可以简化 ${name}
5 Thymeleaf内置对象
dates:⽇期格式化、calendars:⽇期操作、numbers:数字格式化、
strings:字符串格式化、bools:boolean、arrays:数组内置对象、
lists:List集合内置对象、sets:Set集合内置对象、maps:Map集合内置对象
index.html:
date格式化:<span th:text="${#dates.format(date,'yyyy-MM-dd')}"></span><br/>
当前时间:<span th:text="${#dates.createNow()}"></span><br/>
当前日期:<span th:text="${#dates.createToday()}"></span><br/>
Calendar格式化:<span th:text="${#calendars.format(calendar,'yyyy-MM-dd')}"></span><br/>
number百分比格式化(小数点左右保留两位:0.06-->06.00%):
<span th:text="${#numbers.formatPercent(number,2,2)}"></span><br/>
boolean是否为true:<span th:text="${#bools.isTrue(boolean)}"></span><br/>
String类型的name是否为空:<span th:text="${#strings.isEmpty(string)}"></span><br/>
name的长度:<span th:text="${#strings.length(string)}"></span><br/>
String类型的name拼接:<span th:text="${#strings.concat('yu ',string)}"></span><br/>
String类型的name拼接:<span th:text="${#strings.concat(string,' yu')}"></span><br/>
arrays的⻓度:<span th:text="${#arrays.length(array)}"></span><br/>
arrays是否包含jack:<span th:text="${#arrays.contains(array,'jack')}"></span><br/>
List是否为空:<span th:text="${#lists.isEmpty(list)}"></span><br/>
List的⻓度:<span th:text="${#lists.size(list)}"></span><br/>
Set是否为空:<span th:text="${#sets.isEmpty(set)}"></span><br/>
Set的⻓度:<span th:text="${#sets.size(set)}"></span><br/>
Map是否为空:<span th:text="${#maps.isEmpty(map)}"></span><br/>
Map⻓度:<span th:text="${#maps.size(map)}"></span><br/>
Handler:
@GetMapping("/inner")
public ModelAndView inner(){
ModelAndView modelAndView = new ModelAndView("index");
modelAndView.addObject("date",new Date()); //日期
Calendar calendar = Calendar.getInstance();
calendar.set(2022,4,27);
modelAndView.addObject("calendar",calendar);
modelAndView.addObject("number",0.06);
modelAndView.addObject("string","hello world");
modelAndView.addObject("boolean",true);
modelAndView.addObject("array",Arrays.asList("jack","tom"));
List list = new ArrayList<>();
list.add(new User(1,"jack1"));
list.add(new User(2,"tom1"));
modelAndView.addObject("list",list);
Set set = new HashSet<>();
set.add(new User(1,"jack2"));
set.add(new User(2,"tom2"));
modelAndView.addObject("set",set);
Map map = new HashMap<>();
map.put(1,new User(1,"jack3"));
map.put(2,new User(2,"tom3"));
modelAndView.addObject("map",map);
return modelAndView;
}
JdbcTemplate是Spring自带的JDBC模块组件,底层对JDBC进行了封装。用法与mybatis一样,需要自定义sql语句,它实现了数据库的连接,SQL语句的执行,结果集的封装。
缺点:灵活性比如mybatis,因为mybatis的SQL语句定义在xml配置文件中,更有利于维护和扩展。
而JdbcTemplate以硬编码的方式将SQL直接写在Java代码中,不利于维护扩展。
1、pom.xml
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
2、创建实体类
3、创建UserRepository接口以及实现类
@Repository
public class UserRepositoryImpl implements UserRepository {
@Autowired
private JdbcTemplate jdbcTemplate; //直接引入
@Override
public List findAll() {
return jdbcTemplate.query(
"select * from user",
new BeanPropertyRowMapper<>(User.class)
);
}
@Override
public User findById(Integer id) {
return jdbcTemplate.queryForObject(
"select * from user where id = ?",
new Object[]{id},
new BeanPropertyRowMapper<>(User.class)
);
}
@Override
public void save(User user) {
jdbcTemplate.update(
"insert into user(username,password) values(?,?)",
user.getUsername(),
user.getPassword()
);
}
@Override
public void update(User user) {
jdbcTemplate.update(
"update user set username=?,password=? where id=? ",
user.getUsername(),
user.getPassword(),
user.getId()
);
}
@Override
public void delete(Integer id) {
jdbcTemplate.update(
"delete from user where id=?",
id
);
}
}
4、测试
@SpringBootTest
class SpringbootApplicationTests {
@Autowired
private UserRepositoryImpl userRepository;
@Test
void testJdbc() {
List userList = userRepository.findAll();
System.out.println(userList);
}
}
query方法
1、 query(String sql, RowMapper<t> rowMapper)</t>
其中的RowMapper是一个接口,作用是解析结果集,将JDBC查询出来的ResultSet对象转化为POJO。
调用query方法时要指定类的结构 new BeanPropertyRowMapper<>(User.class)
@FunctionalInterface
public interface RowMapper {
@Nullable
T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
2、 queryForObject(String sql, @Nullable Object[] args, RowMapper<t> rowMapper)</t>
该⽅法⽤来 查询⼀条数据,并将结果封装成⼀个POJO
update方法
增加、删除、修改的操作都可以调用个这个方法。
1、pom.xml(spring的web项目)
org.springframework.boot
spring-boot-starter-parent
2.6.7
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.2.2
2、application.yml
#端口
server:
port: 8080
tomcat:
uri-encoding: UTF-8
###############################
mybatis:
mapper-locations: classpath:/mapping/*.xml # mapper.xml文件的路径
type-aliases-package: com.yu.entity # 全限定名(包名+类名)起别名
###############################
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/school?useSSL=false&characterEncoding=utf8&serverTimezone=GMT
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 12345
3、实体类User
4、创建UserRepository接口
public interface UserRepository {
public List findAll();
public User findById(Integer id);
public void save(User user);
public void update(User user);
public void delete(Integer id);
}
5、/resources/mapping创建UserRepository.xml【关注点】
select * from user
select * from user where id=#{id}
insert into user(username,password) values(#{username},#{password})
update user set username=#{usernamw},password=#{password} where id=#{id}
delete from user where id=#{id}
6、创建Handler
@RestController
@RequestMapping("/user")
public class UserHandler {
@Autowired
private UserRepository userRepository;
@GetMapping("/findAll")
public List findAll(){
return userRepository.findAll();
}
@GetMapping("/findById/{id}")
public User findById(@PathVariable("id") Integer id){
return userRepository.findById(id);
}
@PostMapping("/save")
public int save(@RequestBody User user){
return userRepository.save(user);
}
@PutMapping("/update")
public int update(@RequestBody User user){
return userRepository.update(user);
}
@DeleteMapping("/delete/{id}")
public int delete(@PathVariable("id") Integer id){
return userRepository.delete(id);
}
}
7、创建启动类,扫描mapper
@SpringBootApplication
@MapperScan("com.yu.repository") #扫描mapper
public class SpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
}
}
总结:
1、注意application配置文件中,需要配置mybatis的mapper文件路径,以及别名。
2、在resources的mapping文件夹下创建对应的Mapper.xml文件(sql语句),还有命名空间
3、启动类添加注解: @MapperScan(“com.yu.repository”) 。作用是指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类。
JPA和Spring Data JPA的关系
JPA(java persistence API)java持久层规范。定义了一系列ORM接口,它本身不能直接使用,接口必须实现才能使用,Hibernate框架就是一个实现了JPA规范的框架。
Spring Data JPA是Spring框架提供的对JPA规范的抽象,通过约定的命名规范完成持久层接口的编写,
在不需要实现接口的情况下,就可以完成对数据库的操作。
简单理解:通过Spring Data JPA只需要定义接口而不需要实现,就能完成CRUD的操作。
Spring Data JPA本身并不是⼀个具体的实现,它只是⼀个抽象层,底层还是需要Hibernate这样的JPA来提供⽀持。
Hibernate 是一款全自动的 ORM 框架,它能够自动生成的 SQL 语句并自动执行,实现对数据库进行操作,
Spring Data JPA和Spring JdbcTemplate的关系
Spring JdbcTemplate是Spring框架提供的⼀套操作数据库的模版,
Spring Data JPA是JPA的抽象。
1、pom.xml
<!-- Spring Boot 集成 Spring Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2、application.yml
#端口
server:
port: 8080
tomcat:
uri-encoding: UTF-8
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/school?useSSL=false&characterEncoding=utf8&serverTimezone=GMT
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 12345
# 显示sql语句,并格式化
jpa:
show-sql: true
properties:
hibernate:
format_sql: true
3、实体类。完成实体类与数据表的映射【重点】
import javax.persistence.*;
@Data
@Entity(name = "user")//将类与表名联系起来(name为表名)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column
private String username;
@Column
private String password;
}
注解分析:
- @Entity将实体类与数据表进行映射,其中name = "user"指定表名
- @Id将实体类中的成员变量与数据表的主键进行映射,⼀般都是id
- @GeneratedValue表示自动生成主键,strategy为主键选择生成策略(GenerationType.IDENTITY:主键由数据库自动生成(主要是自动增长型))
- @Column将实体类中的成员变量与数据表的普通字段进行映射
4、创建UserRepository
只需要继承JpaRepository,不需要实现方法,也不需要写SQL语句。
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository {
} // 其中JpaRepository,一个指实体类,另一个是表的主键的类型
5、创建Handler
@RestController
@RequestMapping("/user")
public class UserHandler {
@Autowired
private UserRepository userRepository;
@GetMapping("/findAll")
public List findAll(){
return userRepository.findAll();
}
@GetMapping("/findById/{id}")
public User findById(@PathVariable("id") Integer id){
return userRepository.findById(id).get(); // Optional findById(ID id);防止空指针
}
@PostMapping("/save")
public void save(@RequestBody User user){
userRepository.save(user);
}
@PutMapping("/update")
public void update(@RequestBody User user){
userRepository.save(user);
}
@DeleteMapping("/deleteById/{id}")
public void deleteById(@PathVariable("id") Integer id){
userRepository.deleteById(id);
}
}
6、【重点】在继承JpaRepsitory的基础上,开发者也可以自定义方法。
public interface UserRepository extends JpaRepository {
// 这个自定义的方法要特别注意
// By后面的为字段名的首字母大写。不能写其他的,例如findByName则报错
public User findByUsername(String username);
}
@GetMapping("/findByUsername/{username}")
public User findByUsername(@PathVariable("username") String username){
return userRepository.findByUsername(username);
}
Spring Security:利用Spring IoC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。
整合Spring Security
1、创建spring的Maven⼯程,pom.xml
spring-boot-starter-parent
这是Spring Boot的父级依赖,这样当前的项目就是Spring Boot项目了。
spring-boot-starter-parent
是一个特殊的starter,它用来提供相关的Maven默认依赖。使用它之后,常用的包依赖可以省去version标签。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
2、Handler
@Controller
public class SecurityHandler {
@GetMapping("/index")
public String index(){
return "index";
}
}
3、前端thymeleaf的html
<form method="post" action="/logout">
<input type="submit" value="退出">
</form>
4、application.yml
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
5、Application
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
自定义用户密码(默认登录页面)
spring:
thymeleaf:
prefix: classpath:/templates/
suffix: .html
security:
user:
name: admin
password: 12345
权限管理
用户---->角色---->权限:将权限交给角色,再把角色赋予用户。
举例:
定义两个资源:index.html、admin.html
定义两个角色:ADMIN可以访问index.html和admin.html、USER只能访问index.html
1、config包下面创建SecurityConfig类
@Configuration // 配置类
@EnableWebSecurity // 开启web安全验证
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 角色和资源的关系
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/index").access("hasRole('ADMIN') or hasRole('USER')")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.csrf()
.disable();
}
/**
* 用户和角色的关系
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder())
.withUser("user").password(new MyPasswordEncoder()
.encode("000")).roles("USER")
.and()
.withUser("admin").password(new MyPasswordEncoder()
.encode("123")).roles("ADMIN","USER");
}
}
2、自定义MyPassowrdEncoder
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
}
3、Handler
@Controller
public class SecurityHandler {
@GetMapping("/index")
public String index(){
return "index";
}
@GetMapping("/admin")
public String admin(){
return "admin"; //转发到admin页面
}
@GetMapping("/login")
public String login(){
return "login";
}
}
4、login.html
<html xmlns:th="http://www.thymeleaf.org">
<body>
<!-- spring security的param.error -->
<p th:if="${param.error}">
用户名或密码错误
</p>
<form th:action="@{/login}" method="post">
<!-- 这里的name必须是username -->
用户名:<input type="text" name="username"><br/>
密 码:<input type="password" name="password"><br/>
<input type="submit" value="登录">
</form>
</body>
5、index.html(USER、ADMIN)
<body>
<p>欢迎回来</p>
<form method="post" action="/logout">
<input type="submit" value="退出">
</form>
</body>
6、admin.html(ADMIN)
<body>
<p>后台管理系统</p>
<form method="post" action="/logout">
<input type="submit" value="退出">
</form>
</body>