Java经典框架之SpringBoot
SpringBoot
课程内容的介绍
一、SpringBoot基础
1. SpringBoot概念
2. SpringBoot项目构建
2.1 手动创建
2.1.1 创建MAVEN项目
2.1.2 添加依赖
<?xml version="1.0" encoding="UTF-8"?>
<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>com.bobo</groupId><artifactId>SpringBootDemo01</artifactId><version>1.0-SNAPSHOT</version><!-- 1.添加SpringBoot的依赖 --><parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version>2.3.8.RELEASE</version></parent><dependencies><!-- 2. 添加SpringMVC的支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies></project>
2.1.3 创建启动类
package com.bobo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;/*** SpringBoot项目的启动类*/
@SpringBootApplication
public class AppStart {/*** 程序启动的入口* @param args*/public static void main(String[] args) {SpringApplication.run(AppStart.class,args);}
}
2.1.4 启动程序
2.2 在线构建
2.3 IDEA直接创建
3. SpringBoot基本使用
3.1 自定义控制器
package com.bobo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;/*@Controller
@ResponseBody*/
@RestController
public class HelloController {@RequestMapping("/hello")public String hello(){System.out.println("hello ...);return "Hello ...";}
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// 以上四个是JAVA中提供的元注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM,classes = {TypeExcludeFilter.class}
), @Filter(type = FilterType.CUSTOM,classes = {AutoConfigurationExcludeFilter.class}
)}
)
3.2 静态资源
3.3 定制Banner
package com.bobo;import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;/*** @SpringBootApplication 组合注解* @ComponentScan 可以直接扫描路径* 如果没有指定要扫描的特定的路径,* 那么默认的是会把当前注解所在的类的包及其子包作为扫描路径*/
@SpringBootApplication
public class SpringBootDemo03Application {public static void main(String[] args) {SpringApplication app = new SpringApplication(SpringBootDemo03Application.class);app.setBannerMode(Banner.Mode.OFF); // 关闭掉Bannerapp.run(args);}}
3.4 属性文件
3.4.1 默认设置
server.port=8082
server.servlet.context-path=/springboot
3.4.2 自定义属性
# 默认属性修改
server.port=8082
server.servlet.context-path=/springboot
# 自定义属性
user.userName=admin
user.realName=波波
user.address=湖南长沙
package com.bobo.controller;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;/*@Controller
@ResponseBody*/
@RestController
public class HelloController {@Value(value = "${user.userName}")private String userName;@Value(value = "${user.realName}")private String realName;@Value(value = "${user.address}")private String address;@RequestMapping("/hello")public String hello(){System.out.println("hello ..."+ userName + " " + realName + " " + address);return "Hello ...";}
}
3.4.3 yml文件
user.hello.username=a
user.hello.password=123
user.hello.address=cs
user.hello.age=1
user:hello:username:apassword:123address:csage:1
3.5 日志
# 日志配置
#logging.file.path=d:/tools/log
logging.file.name=d:/tools/log/log.log
logging.level.org.springframework.web=DEBUG
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false"><!--日志文件主目录:这里${user.home}为当前服务器用户主目录--><property name="LOG_HOME" value="${user.home}/log"/><!--日志文件名称:这里spring.application.name表示工程名称--><springProperty scope="context" name="APP_NAME" source="spring.application.name"/><!--默认配置--><include resource="org/springframework/boot/logging/logback/defaults.xml"/><!--配置控制台(Console)--><include resource="org/springframework/boot/logging/logback/console-appender.xml"/><!--配置日志文件(File)--><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><!--设置策略--><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!--日志文件路径:这里%d{yyyyMMdd}表示按天分类日志--><FileNamePattern>${LOG_HOME}/%d{yyyyMMdd}/${APP_NAME}.log</FileNamePattern><!--日志保留天数--><MaxHistory>15</MaxHistory></rollingPolicy><!--设置格式--><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern><!-- 或者使用默认配置 --><!--<pattern>${FILE_LOG_PATTERN}</pattern>--><charset>utf8</charset></encoder><!--日志文件最大的大小--><triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"><MaxFileSize>100MB</MaxFileSize></triggeringPolicy></appender><!-- 多环境配置 按照active profile选择分支 --><springProfile name="dev"><!--root节点 全局日志级别,用来指定最基础的日志输出级别--><root level="DEBUG"><appender-ref ref="FILE"/><appender-ref ref="CONSOLE"/></root><!-- 子节点向上级传递 局部日志级别--><logger level="WARN" name="org.springframework"/><logger level="WARN" name="com.netflix"/><logger level="DEBUG" name="org.hibernate.SQL"/></springProfile><springProfile name="prod"><!--root节点 全局日志级别,用来指定最基础的日志输出级别--><root level="INFO"><appender-ref ref="FILE"/><appender-ref ref="CONSOLE"/></root></springProfile>
</configuration>
3.6 Profile
user.host=192.168.100.120
user.host=192.168.111.123
3.7 静态资源文件
## 设置自定义的路径
spring.mvc.static-path-pattern=/**
## 覆盖掉默认的配置录
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,class path:/sfile/
3.8 Servlet操作
3.8.1 Servlet
package com.bobo.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet(name="firstServlet",urlPatterns = "/first")
public class FirstServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("--firstServlet -- doGet 方法");PrintWriter writer = resp.getWriter();writer.write("success");writer.flush();writer.close();}
}
@SpringBootApplication
// 在SpringBoot项目启动的时候会扫描 @WebServlet注解
@ServletComponentScan
public class SpringbootDemo06Application {public static void main(String[] args) {SpringApplication.run(SpringbootDemo06Application.class, args);}
}
package com.bobo.servlet;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;public class SecondServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("--secondServlet -- doGet 方法");PrintWriter writer = resp.getWriter();writer.write("success");writer.flush();writer.close();}
}
@SpringBootApplication
// 在SpringBoot项目启动的时候会扫描 @WebServlet注解
@ServletComponentScan
public class SpringbootDemo06Application {public static void main(String[] args) {SpringApplication.run(SpringbootDemo06Application.class, args);}@Beanpublic ServletRegistrationBean servletRegistrationBean(){ServletRegistrationBean bean = new ServletRegistrationBean(new SecondServlet());bean.addUrlMappings("/second");return bean;}
}
3.8.2 Filter
@WebFilter(urlPatterns = "/first")
public class FirstFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("FirstFilter before");filterChain.doFilter(servletRequest,servletResponse);System.out.println("FirstFilter end");}
}
package com.bobo.filter;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;public class SecondFilter implements Filter {@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("SecondFilter before");filterChain.doFilter(servletRequest,servletResponse);System.out.println("SecondFilter end");}
}
@Beanpublic FilterRegistrationBean filterRegistrationBean(){FilterRegistrationBean bean = new FilterRegistrationBean(new SecondFilter());bean.addUrlPatterns("/second");return bean;}
3.8.3 Listener
package com.bobo.listener;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;@WebListener
public class FirstListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("FirstListener ... 初始化");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("FirstListener ... 销毁");}
}
package com.bobo.listener;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;public class SecondListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("SecondListener ... 初始化");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("SecondListener ... 销毁");}
}
@Beanpublic ServletListenerRegistrationBean servletListenerRegistrationBean(){return new ServletListenerRegistrationBean(new SecondListener());}
3.9 文件上传
3.9.1 表单页面
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>用户管理</title>
</head>
<body><h1>文件上传案例:</h1><form action="/user/upload" method="post" enctype="multipart/form-data" ><label>账号:</label><input type="text" name="username"><br><label>头像:</label><input type="file" name="upload"><br><input type="submit" value="提交"></form>
</body>
</html>
3.9.2 控制器
package com.bobo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;@RestController
@RequestMapping("/user")
public class UserContoller {@RequestMapping("/upload")public String fileUpload(String username, MultipartFile upload) throws IOException {System.out.println(username + " " + upload.getOriginalFilename());upload.transferTo(new File("d:/tools/",upload.getOriginalFilename()));return "success";}}
3.9.3 属性文件设置
server.port=8082spring.servlet.multipart.enabled=true
# 设置单个文件上传的大小
spring.servlet.multipart.max-file-size=20MB
# 设置一次请求上传文件的总的大小
spring.servlet.multipart.max-request-size=200MB
3.9.4 测试
4.SpringBoot基本应用
4.1 Freemaker
4.2 整合Freemaker
4.2.1 添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
4.2.2 配置
spring.freemarker.suffix=.ftl
4.2.3 创建Freemaker文件
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><h1>Hello Freemark ...</h1></body>
</html>
4.2.4 控制器
@Controller
@RequestMapping("/user")
public class UserController {@RequestMapping("/query")public String query(){System.out.println("query ....");return "user";}
}
4.2.5 测试
4.3 Freemaker的基本应用
4.3.1 绑定单个数据
/*** 基本数据类型* 自定义数据类型* 数据容器* @param model* @return*/@RequestMapping("/query")public String query(Model model){System.out.println("query ....");model.addAttribute("userName","波波老师");model.addAttribute("age",18);model.addAttribute("address","湖南长沙");model.addAttribute("flag",true);model.addAttribute("birth",new Date());return "user";}
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><h1>Hello Freemark ...</h1>${userName}<br>${age}<br></body>
</html>
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><h1>Hello Freemark ...</h1>${userName}<br>${age}<br>${address}<br>${flag?string("真","假")}<br></body>
</html>
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><h1>Hello Freemark ...</h1>${userName}<br>${age}<br>${address}<br>${flag?string("真","假")}<br>${birth}<br></body>
</html>
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><h1>Hello Freemark ...</h1>${userName}<br>${age}<br>${address}<br>${flag?string("真","假")}<br>${birth?string("yyyy-MM-dd")}<br></body>
</html>
4.3.2 单个数据处理
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><h1>Hello Freemark ...</h1>${userName}<br>${age}<br>${address}<br>${flag?string("真","假")}<br>${birth?string("yyyy-MM-dd")}<br><hr><#-- 注释符 --><#assign x=3.1415><#assign y=6><!--mN:小数部分最小N位MN:小数部分最大N位-->x=${x}<br>y=${y}<br>#{x;M2}<br><!-- 3.14 -->#{x;m2}<br><!-- 3.14 -->#{y;M2}<br><!-- 6 -->#{y;m2}<br><!-- 6.00 --><body>
</html>
<#assign hello="hello freemarker" >
<#-- 字符串拼接 -->
HELLO-${hello}<br>
<#-- EL表达式中的常量表示 -->
${'HELLO|'+hello}<br>
<#-- 常量中使用数据 -->
${'HELLO*${hello}'}<br>
${userName}----${hello}<br>
${userName+'-->' + hello}<br>
${hello}<br>
${hello[1]}<br>
${hello[4]}<br>
${hello[1..6]}<br>
${hello[3..]}<br>
4.3.3 自定义对象
@RequestMapping("/query1")
public String query1(Model model){User user = new User(666,"admin","123456");model.addAttribute("user",user);return "user1";
}
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><#-- 自定义对象 -->${user.id}<br>--> <#--${user[id]}<br>-->${user.userName}<br>-->${user['userName']}<br>${user.password}<br></body>
</html>
4.3.4 集合对象
@RequestMapping("/query1")public String query1(Model model){User user = new User(666,"admin","123456");model.addAttribute("user",user);Map<String,Object> map = new HashMap<>();map.put("user",user);List list = Arrays.asList("张三","李四","王五");List list1 = Arrays.asList("1111","2222","3333");model.addAttribute("list",list);model.addAttribute("list1",list1);model.addAttribute("map",map);return "user1";}
4.3.5 算数运算
加法: +
减法: -
乘法: *
除法: /
求模 (求余): %
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><h1>算术运算符:</h1><br>${99+100*30}<br>${99/7}<br>${(99/7)?int}<br>${55%3}<br></body>
</html>
4.3.6 比较运算符
4.3.7 逻辑操作
逻辑 或: ||
逻辑 与: &&
逻辑 非: !
4.3.8 内置函数
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><h1>算术运算符:</h1><br>${99+100*30}<br>${99/7}<br>${(99/7)?int}<br>${55%3}<br><h1>内建函数:</h1><#assign hello="Hello FreeMarker"><#assign page="<span style='color:red'>HELLO</span>">${hello}<br>${page}<br>${page?html}<br>${hello?upper_case}<br>${hello?lower_case}<br>${now?date}<br>${now?datetime}<br>${now?time}<br></body>
</html>
4.3.9 分支和循环
<html><head><title>Freemaker</title><meta charset="UTF-8"></head><body><h1>算术运算符:</h1><br>${99+100*30}<br>${99/7}<br>${(99/7)?int}<br>${55%3}<br><h1>内建函数:</h1><#assign hello="Hello FreeMarker"><#assign page="<span style='color:red'>HELLO</span>">${hello}<br>${page}<br>${page?html}<br>${hello?upper_case}<br>${hello?lower_case}<br>${now?date}<br>${now?datetime}<br>${now?time}<br><hr><#assign age = 18 ><#if age == 18>等于18<#elseif age gt 18 >大于18<#else >小于18</#if>null的判断:<br><#assign mypage="a"><#-- ?? 检测值是否存在 --><#if mypage??>mypage存在<#else >mypage不存在</#if><br><#assign i=3><#switch i><#case 1>ok<#break ><#case 2>ok2<#break ><#case 3>ok3<#break ><#default >ok4</#switch><#list list as obj><#if obj=='李四'><#break ></#if>${obj}<br></#list><#assign aaa=555><#-- !的使用--><br>${aaa!"666"}<!-- 如果aaa存在就显示aaa本来的值,如果aaa不存在就显示666 --><br></body>
</html>
5.综合案例
5.1 项目创建
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.bobo</groupId><artifactId>springboot-demo09</artifactId><version>0.0.1-SNAPSHOT</version><name>springboot-demo09</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.14</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
server.port=8082# 配置JDBC的相关信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/logistics?
characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456# 配置连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource# 配置MyBatis的package 设置别名
mybatis.type-aliases-package=com.bobo.pojo
package com.bobo.pojo;public class User {private String user_id ;private String user_name ;private String real_name ;private String password ;private String email ;private String phone ;private String u1 ;private String u2 ;public String getUser_id() {return user_id;}public void setUser_id(String user_id) {this.user_id = user_id;}public String getUser_name() {return user_name;}public void setUser_name(String user_name) {this.user_name = user_name;}public String getReal_name() {return real_name;}public void setReal_name(String real_name) {this.real_name = real_name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getU1() {return u1;}public void setU1(String u1) {this.u1 = u1;}public String getU2() {return u2;}public void setU2(String u2) {this.u2 = u2;}
}
5.2 查询用户信息
package com.bobo.mapper;import com.bobo.pojo.User;import java.util.List;public interface UserMapper {List<User> query();}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bobo.mapper.UserMapper"><select id="query" resultType="user">select * from t_user</select>
</mapper>
package com.bobo.service;import com.bobo.pojo.User;import java.util.List;public interface IUserService {List<User> query();}
package com.bobo.service.impl;import com.bobo.mapper.UserMapper;
import com.bobo.pojo.User;
import com.bobo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class UserServiceImpl implements IUserService {@Autowiredprivate UserMapper mapper;@Overridepublic List<User> query() {return mapper.query();}}
package com.bobo.controller;import com.bobo.pojo.User;
import com.bobo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;import java.util.List;@Controller
@RequestMapping("/user")
public class UserController {@Autowiredprivate IUserService service;@RequestMapping("/query")public String query(Model model){List<User> list = service.query();model.addAttribute("list",list);return "/user";}}
<html><head><title>用户管理</title><meta charset="UTF-8"></head><body><h1>用户管理</h1><table><tr><th>编号</th><th>账号</th><th>姓名</th><th>邮箱</th><th>电话</th><th>操作</th></tr><#list list as user><tr><td>${user.user_id}</td><td>${user.user_name}</td><td>${user.real_name!""}</td><td>${user.email!""}</td><td>${user.phone!""}</td><td>...</td></tr></#list></table></body>
</html>
5.3 添加用户
<html><head><title>用户管理</title><meta charset="UTF-8"></head><body><h1>用户管理</h1><form action="/user/userUpdate" method="post" ><input type="hidden" name="user_id" value="${user.user_id}"><label>账号</label><input type="text" name="user_name" value="${user.user_name}"><br><label>姓名</label><input type="text" name="real_name" value="${user.real_name!""}"><br><label>邮箱</label><input type="text" name="email" value="${user.email!""}"><br><label>电话</label><input type="text" name="phone" value="${user.phone!""}"><br><input type="submit" value="提交"></form></body>
</html>
5.4 更新用户
<html><head><title>用户管理</title><meta charset="UTF-8"></head><body><h1>用户管理</h1><form action="/user/userUpdate" method="post" ><input type="hidden" name="user_id" value="${user.user_id}"><label>账号</label><input type="text" name="user_name"value="${user.user_name}"><br><label>姓名</label><input type="text" name="real_name"value="${user.real_name!""}"><br><label>邮箱</label><input type="text" name="email"value="${user.email!""}"><br><label>电话</label><input type="text" name="phone"value="${user.phone!""}"><br><input type="submit" value="提交"></form></body>
</html>
5.5 删除用户
<html><head><title>用户管理</title><meta charset="UTF-8"></head><body><h1>用户管理</h1><h2><a href="/user/dispatchUpdate">添加用户</a></h2><table><tr><th>编号</th><th>账号</th><th>姓名</th><th>邮箱</th><th>电话</th><th>操作</th></tr><#list list as user><tr><td>${user.user_id}</td><td>${user.user_name}</td><td>${user.real_name!""}</td><td>${user.email!""}</td><td>${user.phone!""}</td><td><a href="/user/dispatchUpdate?id=${user.user_id}">更新</a><a href="/user/deleteUser?id=${user.user_id}">删除</a></td></tr></#list></table></body>
</html>
6. Thymeleaf
6.1 SpringBoot整合
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.bobo</groupId><artifactId>springboot-demo10</artifactId><version>0.0.1-SNAPSHOT</version><name>springboot-demo10</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- 使用Thymeleaf需要添加的依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Thymeleaf介绍</title>
</head>
<body><h1>Hello Thymeleaf</h1></body>
</html>
@Controller
public class UserController {@RequestMapping("/hello")public String hello(){System.out.println("hello ....");return "/user";}
}
6.2 Thymeleaf基本使用
6.2.1 变量输出
@RequestMapping("/hello")
public String hello(Model model){System.out.println("hello ....");model.addAttribute("hello","Hello Thymeleaf");model.addAttribute("msg","hahaha");model.addAttribute("now",new Date());model.addAttribute("flag",true);model.addAttribute("age",18);return "/user";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Thymeleaf介绍</title>
</head>
<body><h1>Hello Thymeleaf</h1><label th:text="hello"></label><br><label th:text="${hello}"></label><br><label th:text="${now}"></label><br><label th:text="${flag}"></label><br><label th:text="${age}"></label><br><h2>th:value的使用</h2><input type="text" value="aaa"><br><input type="text" th:value="${msg}"><br>
</body>
</html>
6.2.2 内置函数
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Thymeleaf介绍</title>
</head>
<body><h1>string类型介绍</h1>hello:<span th:text="${hello}"></span><br>hello是否为空:<span th:text="${#strings.isEmpty(hello)}"></span><br>hello字符串是否包含"th":<span th:text="${#strings.contains(hello,'th')}">
</span><br>hello字符串是否包含"Th":<span th:text="${#strings.contains(hello,'Th')}">
</span><br>hello以H开头:<span th:text="${#strings.startsWith(hello,'H')}"></span><br>hello以a开头:<span th:text="${#strings.startsWith(hello,'a')}"></span><br>hello以H结尾:<span th:text="${#strings.endsWith(hello,'H')}"></span><br>hello以a结尾:<span th:text="${#strings.endsWith(hello,'a')}"></span><br>hello的长度:<span th:text="${#strings.length(hello)}"></span><br>hello都大写:<span th:text="${#strings.toUpperCase(hello)}"></span><br>hello都小写:<span th:text="${#strings.toLowerCase(hello)}"></span><br>
</body>
</html>
<h1>日期时间处理</h1>
时间:<span th:text="${now}"></span><br>
时间:<span th:text="${#dates.format(now)}"></span><br>
时间:<span th:text="${#dates.format(now,'yy/MM/dd')}"></span><br>
时间:<span th:text="${#dates.format(now,'yy/MM/dd hh:ss:mm')}"></span><br>
时间:<span th:text="${#dates.format(now,'yy/MM/dd HH:ss:mm')}"></span><br>
年份:<span th:text="${#dates.year(now)}"></span><br>
月份:<span th:text="${#dates.month(now)}"></span><br>
日期:<span th:text="${#dates.day(now)}"></span><br>
本周的第几天:<span th:text="${#dates.dayOfWeek(now)}"></span><br>
小时:<span th:text="${#dates.hour(now)}"></span><br>
6.2.3 条件判断
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Thymeleaf介绍</title>
</head>
<body><h1>条件判断</h1><h2>if语句</h2><span th:if="${sex} == '男'">男</span><span th:unless="${sex} =='男'">女</span><br><!-- and or not --><span th:if="${flag or false}">or的使用11</span><span th:unless="${flag or false}">or的使用12</span><br><span th:if="${flag and false}">and的使用21</span><span th:unless="${flag and false}">and的使用22</span><br><span th:if="${not flag}">not的使用11</span><span th:unless="${not flag}">not的使用22</span><br><!-- 三木运算符 --><span th:text="true?'A':'B'"></span><br><!-- switch语句 --><hr><div th:switch="${age}"><div th:case="17">17岁</div><div th:case="18">18岁</div><div th:case="19">19岁</div><div th:case="*">其他...</div></div>
</body>
</html>
6.2.4 循环语句
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Thymeleaf介绍</title>
</head>
<body><h1>循环判断</h1><div th:each="c : ${list1}"><span th:text="${c}"></span><br></div><hr><div th:each="user : ${list2}"><span th:text="${user.id}"></span> <span th:text="${user.userName}"></span> <span th:text="${user.address}"></span><br></div><hr><div th:each="m : ${map}"><!-- 每次循环获取的是一个KV对 --><span th:text="${m.getKey() + ':' + m.getValue().getId()}"></span><span th:text="${m.getKey() + ':' + m.getValue().getUserName()}"></span><span th:text="${m.getKey() + ':' + m.getValue().getAddress()}"></span></div><hr><div th:each="user,iter : ${list2}"><span th:text="${iter.count}"></span> <span th:text="${iter.index}"></span> <span th:text="${user.id}"></span> <span th:text="${user.userName}"></span> <span th:text="${user.address}"></span><br></div>
</body>
</html>
6.2.5 域对象的操作
@RequestMapping("/hello4")
public String hello4(HttpServletRequest request){request.setAttribute("req","request msg ...");request.getSession().setAttribute("sess","session msg ....");request.getServletContext().setAttribute("app","application msg ....");return "/user4";
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Thymeleaf介绍</title>
</head>
<body><h1>域对象使用</h1><h2>request:</h2><span th:text="${#httpServletRequest.getAttribute('req')}"></span><br><span th:text="${#request.getAttribute('req')}"></span><br><span th:text="${req}"></span><br><h2>session:</h2><span th:text="${#httpSession.getAttribute('sess')}"></span><br><span th:text="${#session.getAttribute('sess')}"></span><br><h2>servletContext:</h2><span th:text="${#servletContext.getAttribute('app')}"></span><br>
</body>
</html>
6.2.6 URL表达式
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Thymeleaf介绍</title>
</head>
<body><h1>URL使用</h1><a href="http://www.baidu.com">百度</a><br><a th:href="@{http://www.baidu.com}">百度</a><br><hr><a th:href="@{/show}">相对路径</a><br><a th:href="@{~/project2/app1}">相对于服务器的根</a><br><a th:href="@{/show(id=1,name=aaa)}">相对路径--参数传递</a><br><a th:href="@{/path/{id}/show(id=66,name=123)}">RestFul支持</a>
</body>
</html>
6.2.7 整合案例改造
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>用户管理</h1>
<h2><a th:href="@{/user/dispatchUpdate}">添加用户</a>
</h2><table><tr><th>编号</th><th>账号</th><th>姓名</th><th>邮箱</th><th>电话</th><th>操作</th></tr><tr th:each="user : ${list}"><td th:text="${user.user_id}"></td><td th:text="${user.user_name}"></td><td th:text="${user.real_name}"></td><td th:text="${user.email}"></td><td th:text="${user.phone}"></td><td><a th:href="@{/user/dispatchUpdate(id=${user.user_id})}">更新</a><a th:href="@{/user/deleteUser(id=${user.user_id})}">删除</a></td></tr></table>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form th:action="@{/user/userUpdate}" method="post" ><span th:if="${user}"><input type="hidden" name="user_id" th:value="${user.user_id}"></span><label>账号</label><input type="text" name="user_name" th:value="${ user==null ?'':user.user_name}"><br><label>姓名</label><input type="text" name="real_name" th:value="${user==null ?'':user.real_name}"><br><label>邮箱</label><input type="text" name="email" th:value="${user==null ?'':user.email}"><br><label>电话</label><input type="text" name="phone" th:value="${user==null ?'':user.phone}"><br><input type="submit" value="提交"></form>
</body>
</html>
二、SpringBoot高级
1.热部署
1.1 放开配置
1.2 注册
1.3 添加devtools
<!--devtools 热部署的支持 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId>
</dependency>
2. 异常处理
2.1 自定义错误页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>系统出错,请联系管理员....</h1><span th:text="${exception}"></span>
</body>
</html>
2.2 @ExceptionHandle注解
package com.bobo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;@Controller
public class UserController {@RequestMapping("/show1")public String showInfo1(){String name = null;// 模拟 空指针异常name.length();return "index";}@RequestMapping("/show2")public String showInfo2(){int a = 1/0; // 默认算术异常return "index";}@ExceptionHandler(value = {NullPointerException.class})public ModelAndView nullPointerExceptionHandler(Exception e){ModelAndView mm = new ModelAndView();mm.addObject("error",e.toString());mm.setViewName("error1");return mm;}@ExceptionHandler(value = {ArithmeticException.class})public ModelAndView arithmeticException(Exception e){ModelAndView mm = new ModelAndView();mm.addObject("error",e.toString());mm.setViewName("error2");return mm;}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>系统出错,请联系管理员....nullPointerExceptionHandler</h1><span th:text="${error}"></span>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>系统出错,请联系管理员....arithmeticException</h1><span th:text="${error}"></span>
</body>
</html>
2.3 @ControllerAdvice注解
package com.bobo.exception;import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;// @ControllerAdvice
public class GlobalException {//@ExceptionHandler(value = {NullPointerException.class})public ModelAndView nullPointerExceptionHandler(Exception e){ModelAndView mm = new ModelAndView();mm.addObject("error",e.toString());mm.setViewName("error1");return mm;}//@ExceptionHandler(value = {ArithmeticException.class})public ModelAndView arithmeticException(Exception e){ModelAndView mm = new ModelAndView();mm.addObject("error",e.toString());mm.setViewName("error2");return mm;}
}
package com.bobo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;@Controller
public class UserController {@RequestMapping("/show1")public String showInfo1(){String name = null;// 模拟 空指针异常name.length();return "index";}@RequestMapping("/show2")public String showInfo2(){int a = 1/0; // 默认算术异常return "index";}
}
2.4 SimpleMappingExceptionResolver
package com.bobo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;import java.util.Properties;@SpringBootApplication
public class SpringbootDemo11Application {public static void main(String[] args) {SpringApplication.run(SpringbootDemo11Application.class, args);}/*** 通过SimpleMappingExceptionResolver 设置 特定异常和 处理器的映射关系* @return*/// @Beanpublic SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();Properties properties = new Properties();properties.put("java.lang.NullPointerException","error1");properties.put("java.lang.ArithmeticException","error2");resolver.setExceptionMappings(properties);return resolver;}
}
2.5 HandleExceptionResolver处理
package com.bobo.exception;import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyHandleExceptionResolver implements HandlerExceptionResolver {@Overridepublic ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {ModelAndView mm = new ModelAndView();if(e instanceof NullPointerException){mm.setViewName("error1");}else if(e instanceof ArithmeticException){mm.setViewName("error2");}else{mm.setViewName("error");}return mm;}
}
3. 单元测试
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions>
</dependency>
package com.bobo.service.impl;import com.bobo.service.IUserService;
import org.springframework.stereotype.Service;import java.util.Arrays;
import java.util.List;@Service
public class UserServiceImpl implements IUserService {@Overridepublic List<String> query() {return Arrays.asList("张三","李四","王五");}
}
package com.bobo;import com.bobo.service.IUserService;
import net.bytebuddy.asm.Advice;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
class SpringbootDemo12ApplicationTests {@Autowiredprivate IUserService service;@Testvoid contextLoads() {System.out.println("---->" + service.query());}@BeforeEachvoid before(){System.out.println("before ...");}@AfterEachvoid after(){System.out.println("after ...");}}
4. 整合Shiro
4.1 项目准备
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.8</version></dependency><!--devtools 热部署的支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency><dependencies>
server.port=8082# 配置JDBC的相关信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/logistics?
characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456# 配置连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource# 配置MyBatis的package 设置别名
mybatis.type-aliases-package=com.bobo.pojo# 指定映射文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml
package com.bobo.service;import com.bobo.pojo.User;import java.util.List;public interface IUserService {public User login(String userName);public List<User> query(User user);
}
package com.bobo.service.impl;import com.bobo.mapper.UserMapper;
import com.bobo.pojo.User;
import com.bobo.pojo.UserExample;
import com.bobo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class UserServiceImpl implements IUserService {@Autowiredprivate UserMapper mapper;@Overridepublic User login(String userName) {User user = new User();user.setUserName(userName);List<User> list = this.query(user);if(list != null && list.size() == 1){return list.get(0);}return null;}@Overridepublic List<User> query(User user) {UserExample example = new UserExample();UserExample.Criteria criteria = example.createCriteria();if(user != null){if(!"".equals(user.getUserName()) && user.getUserName() != null){criteria.andUserNameEqualTo(user.getUserName());}}return mapper.selectByExample(example);}
}
4.2 Shiro整合
4.2.1 Shiro的依赖
<dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.3.2</version>
</dependency>
4.2.2 自定义Realm
package com.bobo.realm;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;public class MyRealm extends AuthorizingRealm {@Autowiredprivate IUserService service;/*** 认证* @param authenticationToken* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {return null;}/*** 授权* @param principalCollection* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}
}
4.2.3 Shiro的配置
package com.bobo.config;import com.bobo.realm.MyRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import org.apache.shiro.mgt.SecurityManager;import java.util.HashMap;
import java.util.Map;@Configuration
public class ShiroConfig {/*** 配置凭证匹配器* @return*/@Beanpublic HashedCredentialsMatcher hashedCredentialsMatcher(){HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();matcher.setHashAlgorithmName("md5");matcher.setHashIterations(1024);return matcher;}/*** 注册自定义的Realm* @param hashedCredentialsMatcher* @return*/@Beanpublic MyRealm myRealm(CredentialsMatcher hashedCredentialsMatcher){MyRealm realm = new MyRealm();realm.setCredentialsMatcher(hashedCredentialsMatcher);return realm;}/*** 注册SecurityManager对象* @return*/@Beanpublic SecurityManager securityManager(Realm myRealm){DefaultWebSecurityManager manager = new DefaultWebSecurityManager();manager.setRealm(myRealm);return manager;}/*** 注册ShiroFilterFactoryBean* @return*/@Bean(name = "shiroFilter")public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager manager){ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();filter.setSecurityManager(manager);filter.setLoginUrl("/login.do");filter.setSuccessUrl("/success.html");filter.setUnauthorizedUrl("/refuse.html");// 设置过滤器Map<String,String> map = new HashMap<>();map.put("/css/**","anon");map.put("/img/**","anon");map.put("/js/**","anon");map.put("/login","anon");map.put("/login.do","authc");map.put("/**","authc");filter.setFilterChainDefinitionMap(map);return filter;}
}
4.2.4 测试
package com.bobo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class LoginController {@RequestMapping("/login")public String goLoginPage(){return "login";}
}
package com.bobo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("/user")
public class UserController {@RequestMapping("/query")public String query(){System.out.println("----user query----");return "user";}
}
4.3 认证实现
4.3.1 自定义Realm
package com.bobo.realm;import com.bobo.pojo.User;
import com.bobo.service.IUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.SimpleByteSource;
import org.springframework.beans.factory.annotation.Autowired;public class MyRealm extends AuthorizingRealm {@Autowiredprivate IUserService service;/*** 认证* @param authenticationToken* @return* @throws AuthenticationException*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String userName = token.getUsername();User user = new User();user.setUserName(userName);// 账号验证user = service.login(userName);if(user == null){return null;}return new SimpleAuthenticationInfo(user,user.getPassword(),new SimpleByteSource(user.getU1()) ,"myRealm");}/*** 授权* @param principalCollection* @return*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}
}
4.3.2 控制器
package com.bobo.controller;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;@Controller
public class LoginController {@RequestMapping("/login")public String goLoginPage(){return "login";}@RequestMapping("/login.do")public String login(HttpServletRequest request){Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);System.out.println("认证错误的信息:" + obj);return "/login";}@RequestMapping("/logout")public String logout(){SecurityUtils.getSubject().logout();return "/login";}
}
4.3.3 登录页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>登录页面</h1><form th:action="@{/login.do}" method="post">账号:<input type="text" name="username" th:value="'admin1'"><br>密码:<input type="password" name="password" th:value="'123'"><br><input type="submit" value="提交"></form>
</body>
</html>
5. 授权操作
5.1 注解的使用
/**
* 开启对Shiro授权注解的支持
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();advisor.setSecurityManager(securityManager);return advisor;
}
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {User user = (User) principalCollection.getPrimaryPrincipal();System.out.println("获取授权的账号:" + user.getUserName());SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();info.addRole("role1");return info;
}
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId>
</dependency>
5.2 标签的使用
<dependency><groupId>com.github.theborakompanioni</groupId><artifactId>thymeleaf-extras-shiro</artifactId><version>2.0.0</version>
</dependency>
@Bean
public ShiroDialect shiroDialect(){return new ShiroDialect();
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>用户管理</h1><shiro:authenticated>已登录:<shiro:principal property="userName"></shiro:principal></shiro:authenticated><a href="#" shiro:hasRole="role1">用户查询</a><a href="#" shiro:hasRole="role1">用户添加</a><a href="#" shiro:hasRole="role2">用户修改</a><a href="#" shiro:hasRole="role2">用户删除</a>
</body>
</html>
相关文章:

Java经典框架之SpringBoot
SpringBoot Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. SpringBoot基础 2. Spring…...
LeetCode75| 二叉搜索树
目录 700 二叉搜索树中的搜索 迭代 递归 450 删除二叉搜索树中的节点 700 二叉搜索树中的搜索 注意二叉搜索树的性质即可 迭代 class Solution { public:TreeNode* searchBST(TreeNode* root, int val) {while(root ! NULL){if(root->val < val)root root->r…...

博物馆3d虚拟场景复原制作有助于传承和弘扬中华民族优秀传统文化
古建筑3D虚拟复原是一种利用现代科技手段对古代建筑进行数字化保护和展示的方法。它通过高精度的三维扫描技术,将古建筑的形态、结构、材料等信息转化为数字化数据,再通过计算机图形学技术将这些数据重建为虚拟的三维模型。这种技术在古建筑保护、研究、…...

二维码地址门牌系统:便捷报修服务引领社区新篇章
文章目录 前言一、二维码门牌系统介绍二、便捷报修服务三、多功能应用四、技术发展与应用前景 前言 科技的快速发展引领了社区生活的新变革,其中二维码门牌系统技术在社区管理方面带来了极大的便利和智能化服务。本文将深入了解这项创新技术及其优势。 一、二维码门…...

c++基础(对c的扩展)
文章目录 命令空间引用基本本质引用作为参数引用的使用场景 内联函数引出基本概念 函数补充默认参数函数重载c中函数重载定义条件函数重载的原理 命令空间 定义 namespace是单独的作用域 两者不会相互干涉 namespace 名字 { //变量 函数 等等 }eg namespace nameA {int num;v…...

RS485数据采集模块,如何一次采集多个modbus设备数据?
在工业数据采集中,RS485是一种常见的数据通信协议,而Modbus则是其上的常用设备协议。那么,如何用一个模块高效采集多个Modbus设备的数据呢?这就是我们今天要探讨的话题! 什么是RS485数据采集模块? 首先&a…...
面试 Vue 框架八股文十问十答第一期
面试 Vue 框架八股文十问十答第一期 作者:程序员小白条,个人博客 相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新! ⭐点赞⭐收藏⭐不迷路!⭐ 1)MVVM 的理解 MVVM (Mod…...

【积微成著】性能测试调优实战与探索(存储模型优化+调用链路分析)| 京东物流技术团队
一、前言 性能测试之于软件系统,是保障其业务承载能力及稳定性的关键措施。以软件系统的能力建设为主线,系统能力设计工作与性能测试工作,既有先后之顺序,亦有相互之影响。以上,在性能测试的场景决策,架构…...

建立分位制,用标准去量化优化效果 - 启动优化为例
Android开发的四年多时间中,逐渐将自己的工作重心从业务移动到小型项目的架构设计,在此过程中代码的书写有了更高的标准和要求,性能优化从此伴随着工作脚步, 为什么要进行性能优化呢? 页面访问时长从1s增加到3s&#…...

Modbus 通信协议 二
Modbus 常用缩写 通用Modbus帧结构 -应用数据单元(ADU) Modbus数据模型 Modbus ADU 和 PDU 的长度 Modbus PDU结构 串行链路上的 Modbus 帧结构 Modbus 地址规则 ASCLL 模式 和 RTU 模式的比较 RTU 模式 RTU 模式位序列 帧格式 帧的标识与鉴别 CRC 循环冗…...

关于系统设计的一些思考
0.前言 当我们站在系统设计的起点,面对一个新的需求,我们该如何开始呢?这是许多处于系统分析与设计领域的新手常常思考的问题。有些人可能会误以为,只要掌握了诸如面向对象、统一建模语言、设计模式、微服务、Serverless、Servic…...

Java 第19章 IO流 课堂练习+本章作业
文章目录 Buffered流拷贝二进制文件创建文件写入文本读取文本文件存读Properties文件 Buffered流拷贝二进制文件 package com.hspedu.chapter19.outputStream;import java.io.*;public class BufferedCopy02 {public static void main(String[] args) {String srcFilePath &q…...

一键制作电子样册,提升企业品牌形象
电子样册作为一种新型的宣传方式,具有许多优势。首先,它打破了传统纸质宣传册的局限性,可以随时随地展示企业的产品和服务。其次,电子样册可以通过多媒体形式展示企业的品牌形象,包括图片、视频、文字等多种形式&…...

Linux 的引导与服务控制
一 开机启动过程 bios加电自检-->mbr-->grub-->加载内核文件-->启动进程 1 bios家电自检 检测硬件是否正常,然后根据bios中的启动项设置,去找内核文件 2 mbr 因为grup太大,第一个扇区存不下所有的grub程序,所以分为2部分指…...

多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测
多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测 目录 多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测预测效果基本介绍模型背景程序设计参考资料 预测效果 基本介绍 MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入…...

高端电流检测方案
随着过去传统的“开环”系统被智能和高效率“闭环”设计所取代,准确的电流检测在多种应用中变得越来越重要。常见的电流检测方法,需要将检流电阻串联进被测电流通路,再用放大电路放大检流电阻上的压降。这个放大电路常被称之为电流检测放大器…...

IP地址、子网掩码与网络地址
一、IP地址 在 TCP/IP 体系中,IP 地址是一个最基本的概念。IP地址的作用:实现和网上的其他设备进行通信 IP地址的表示方法 互联网上的每台主机(或路由器)的每个接口都分配一个全世界唯一的IP地址。该IP地址由ICANN分配。 IP地址…...

python 深度学习 记录遇到的报错问题10
本篇继python 深度学习 解决遇到的报错问题9_module d2l.torch has no attribute train_ch3-CSDN博客 一、CUDA error: no kernel image is available for execution on the device CUDA kernel errors might be asynchronously reported at some other API call,so the stackt…...

linux下docker搭建Prometheus +SNMP Exporter +Grafana进行核心路由器交换机监控
一、安装 Docker 和 Docker Compose https://docs.docker.com/get-docker/ # 安装 Docker sudo apt-get update sudo apt-get install -y docker.io# 安装 Docker Compose sudo apt-get install -y docker-compose二、创建配置文件及测试平台是否正常 1、选个文件夹作为自建…...

Github 2023-12-31 开源项目日报 Top10
根据Github Trendings的统计,今日(2023-12-31统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量TypeScript项目3Swift项目1Java项目1HTML项目1Astro项目1Python项目1C项目1Dart项目1Jupyter Notebook项目1C项…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...