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项…...
管程-第三十三天
目录 为什么要引入管程 管程的定义和基本特征 用管程解决生产者消费者问题 结论 本节思维导图 为什么要引入管程 原因:在解决进程的同步与互斥问题时,信号量机制存在编写困难和易出错的问题 能不能设计一种机制,让程序员写程序时不再需…...
嵌入式中断理解
一、概念 中断: 在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。 中断优先级&#x…...
React16源码: Hooks源码实现
Hooks 1 )概述 Hooks 在 React16.7版本出现的新功能Hooks 改变了整体应用开发的模式,同时开发体验会和以前会变得不一样Hooks 让函数组件具有类组件的能力 在 function component 里面没有this无法保存 state通过 Hooks可以让 function component 代替…...
华为端口隔离高级用法经典案例
最终效果: pc4不能ping通pc5,pc5能ping通pc4 pc1不能和pc2、pc3通,但pc2和pc3能互通 vlan batch 2 interface Vlanif1 ip address 10.0.0.254 255.255.255.0 interface Vlanif2 ip address 192.168.2.1 255.255.255.0 interface MEth0/0/1 i…...
java项目启动jar包启动参数设置端口号
默认启动 java -jar myapp.jar 指定配置文件 java -jar myapp.jar --spring.profiles.activedev 指定端口号 java -jar myapp.jar --server.port8080 后台启动 nohup java -jar myapp.jar --server.port8080 >outlog.log 2>&1 &...
【数据结构和算法】寻找数组的中心下标
其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 前缀和的解题模板 2.1.1 最长递增子序列长度 2.1.2 寻找数组中第 k 大的元素 2.1.3 最长公共子序列…...
多粒度在研究中的应用
FontDiffuser: One-Shot Font Generation via Denoising Diffusion with Multi-Scale Content Aggregation and Style Contrastive Learning 存在的问题 现有的字体生成方法虽然取得了令人满意的性能,但在处理复杂字和风格变化较大的字符(尤其是中文字符)时&#x…...
Docker命令---查看容器日志
介绍 使用docker命令查看容器输出的日志 示例 docker logs 容器ID...
Spring Boot 基于Redisson实现注解式分布式锁
依赖版本 JDK 17 Spring Boot 3.2.0 Redisson 3.25.0 源码地址:Gitee 导入依赖 <properties><redisson.version>3.25.0</redisson.version> </properties><dependencies><dependency><groupId>org.projectlombok</…...
Javascript 正则表达式零宽断言
在介绍正则表达式零宽断言这个概念之前,先看一下以下这道有关 javascript 正则表达式的题目: 登录注册流程是前端最常见的业务流程之一,注册流程少不了密码强弱度校验,请实现对密码的校验,要求满足: 包含大…...
怎么查那些人输入做网站/seo技术培训江门
神经网络的梯度下降(Gradient descent for neural networks) 假设单隐层神经网络会有W[1]W^{[1]}W[1],b[1]b^{[1]}b[1],W[2]W^{[2]}W[2],b[2]b^{[2]}b[2]这些参数,还有个nxn_xnx表示输入特征的个数&…...
阿里云部署一个自己做的网站/菏泽seo
http://www.bootcss.com/p/chart.js/docs/...
昆明企业免费建站/营销推广文案
如果可以有一家公司在移动互联网领域击败苹果,那么应该只有Google! 苹果对本地应用的死忠正是web之王Google的矛头所指。一份分析指出,web和html5将在接下来的四年里面将苹果的经营利润削掉30%,因为应用开发者们正在开发跨设备的…...
网站是如何盈利/电商网站建设报价
...
静态页优秀网站/seo排名赚钱
《C4D的十万个为什么》首发于 公众号:苦七君 免费搜索查看更多问题:kuqijun.com 问题: C4D不能加载object文件,obj文件?提示未知文件格式 答案: 要显示文件名后缀看一下,有时候在文件类型里面…...
做目录网站注意/营销的目的有哪些
通常项目中src下的子目录都会有一个style文件夹,专门用来存放全局的样式文件。这个style文件夹下,一般有reset.css、var.scss、mixin.scss、class.scss、index.scss一般都会在index.scss文件中引入其他文件做统一管理,并在main.js中引入index…...