配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili
【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili
Thymeleaf是一个用于web和独立环境的现代服务器端Java模板引擎。
Jsp也是Java模板引擎,Thymeleaf完全可以用来替代Jsp,在使用时Jsp和Thymeleaf不要混用
--摘自官网Thymeleaf
Thymeleaf是跟Velocity、FreeMarker类似的模板引擎,它可以完全替代JSP,相较与其他的模板引擎相比, Thymeleaf在有网络和无网络的环境下皆可运行,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。注意:使用时必须要经过controller。
pom.xml引入依赖
<!--引入thymeleaf依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
application.yml编写配置
server:
port: 8888
servlet:
context-path: /spring-boot-day7
# 配置Thymeleaf
spring:
thymeleaf:
prefix: classpath:/templates/ # 指定Thymeleaf前缀目录
suffix: .html # 指定模板后缀是否开启Thymeleaf缓存,默认是true开启缓存
# 在开发过程中推荐使用false(类似jsp加载)
编写控制器测试
package com.study.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @ClassName HelloController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/11 15:59
* @Version 1.0
*/
@Controller //一定要是@Controller,不能再使用@RestController注解
@RequestMapping("hello")
public class HelloController {
@RequestMapping("hello")
public String hello(){
System.out.println("测试springboot与Thymeleaf的集成");
return "index";// templates/index.html,最终封装成index.html进行返回
// 直接访问根路径(http://localhost:8888/spring-boot-day7/)加载出index.html,但无渲染效果
}
}
在templates目录中定义模板index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>测试SpringBoot与Thymeleaf的集成</title> </head> <body> <h1>Hello,Thymeleaf!</h1> </body> </html>
测试路径:直接访问根路径定位到templates/index.html
http://localhost:8888/spring-boot-day7/

http://localhost:8888/spring-boot-day7/hello/hello

新建demo.html用于页面展示
使用Thymeleaf时必须在html页面中加入唯一的命名空间(namespace):Thymeleaf简写th,在xmlns:名字处写th
<html lang="en" xmlns:th="http://www.thymeleaf.org">
注意:有的插件可以导入/提示命名空间!
初始的demo.html页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用来测试Thymeleaf语法</title>
</head>
<body>
<h1>测试Thymeleaf语法基本使用</h1>
</body>
</html>
新建控制器DemoController
package com.study.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* @ClassName DemoController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/13 20:36
* @Version 1.0
*/
@Controller
@RequestMapping("demo")
public class DemoController {
@RequestMapping("demo")
public String demo(HttpServletRequest request, Model model, HttpSession session){
System.out.println("demo ok!");
return "demo"; //templates/demo.html,最终封装成demo.html进行返回
}
}

DemoController
package com.study.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* @ClassName DemoController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/13 20:36
* @Version 1.0
*/
@Controller
@RequestMapping("demo")
public class DemoController {
@RequestMapping("demo")
//model底层封装的也是request作用域
public String demo(HttpServletRequest request, Model model, HttpSession session){
System.out.println("demo ok!");
/**
* 1.传递单个数据:String、Integer、解析超链接
*/
String name = "小崔";
request.setAttribute("name",name);
Integer age = 27;
model.addAttribute("age",age);
String content = "<a href='http://www.baidu.com'>百度一下</a>";
model.addAttribute("content",content);
return "demo";
}
}
demo.html
<h2>1.获取单个数据</h2>
<!--
th:text="${属性名}"获取request作用域数据:直接将获取到的数据以文本形式渲染到页面中
th:utext="${属性名}"获取request作用域数据:先将获取到的数据解析成html标签,再以文本形式渲染到页面中
-->
<h3>String类型数据:<span th:text="${name}"/></h3>
<h3>Integer类型数据:<span th:text="${age}"/></h3>
<h3>超链接:<span th:utext="${content}"/></h3>
<h3>输入框:</h3>
<input type="text" name="username" th:value="${name}">
<input type="text" name="age" th:value="${age}">
新建对象User
package com.study.entity;
import java.util.Date;
/**
* @ClassName User
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/13 20:33
* @Version 1.0
*/
public class User {
private Integer id;
private String name;
private Double salary;
private Date birthday;
public User() {
}
public User(Integer id, String name, Double salary, Date birthday) {
this.id = id;
this.name = name;
this.salary = salary;
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", salary=" + salary +
", birthday=" + birthday +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
DemoController
package com.study.controller;
import com.study.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* @ClassName DemoController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/13 20:36
* @Version 1.0
*/
@Controller
@RequestMapping("demo")
public class DemoController {
@RequestMapping("demo")
//model底层封装的也是request作用域
public String demo(HttpServletRequest request, Model model, HttpSession session){
System.out.println("demo ok!");
/**
* 2.传递对象类型数据
*/
User user = new User(1,"小崔",1234.56,new Date());
model.addAttribute("user",user);
return "demo";
}
}
demo.html
<h2>2.获取对象类型数据</h2>
<h3>
user.id:<span th:text="${user.id}"/><br>
user.name:<span th:text="${user.name}"/><br>
user.salary:<span th:text="${user.salary}"/><br>
<!--格式化日期:${#dates.format(格式化值,'格式化的格式')}},其中,dates.format为内置函数-->
user.birthday:<span th:text="${#dates.format(user.birthday,'yyyy-MM-dd HH:mm:ss')}"/>
</h3>
DemoController
package com.study.controller;
import com.study.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* @ClassName DemoController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/13 20:36
* @Version 1.0
*/
@Controller
@RequestMapping("demo")
public class DemoController {
@RequestMapping("demo")
//model底层封装的也是request作用域
public String demo(HttpServletRequest request, Model model, HttpSession session){
System.out.println("demo ok!");
/**
* 3.传递集合类型数据
*/
List<User> users = Arrays.asList(
new User(11,"熊大",1111.11,new Date()),
new User(22,"熊二",2222.22,new Date()),
new User(33,"光头强",3333.33,new Date())
);
model.addAttribute("users",users);
return "demo";
}
}
demo.html
<h2>3.获取集合类型数据</h2>
<ul>
<!--遍历数据:th:each="变量(current_element当前遍历元素),变量(state遍历状态对象):集合"-->
<li th:each="user,state:${users}">
state count: <span th:text="${state.count}"></span>
state odd: <span th:text="${state.odd}"></span>
state even: <span th:text="${state.even}"></span>
state size: <span th:text="${state.size}"></span>
id: <span th:text="${user.id}"></span>
name: <span th:text="${user.name}"></span>
salary: <span th:text="${user.salary}"></span>
birthday: <span th:text="${#dates.format(user.birthday,'yyyy年MM月dd日')}"></span>
</li>
</ul>
补充:展示多条数据
直接遍历集合
<ul th:each="user:${users}">
<li th:text="${user.id}"></li>
<li th:text="${user.name}"></li>
<li th:text="${user.age}"></li>
<li th:text="${#dates.format(user.bir,'yyyy-MM-dd')}"></li>
</ul>
遍历时获取遍历状态
<ul th:each="user,userStat:${users}">
<li><span th:text="${userStat.count}"/>-<span th:text="${user.id}"/></li> 获取遍历次数 count 从1开始 index 从0开始
<li><span th:text="${userStat.odd}"/>-<span th:text="${user.name}"/></li> 获取当前遍历是否是奇数行
<li><span th:text="${userStat.even}"/>-<span th:text="${user.age}"/></li> 获取当前遍历是否是偶数行
<li><span th:text="${userStat.size}"/>-<span th:text="${user.bir}"/></li> 获取当前集合的总条数
</ul>
demo.html
<h2>4.有条件的展示数据</h2>
<!-- th:if="${age>=25}" 作用:有条件的显示数据-->
<div style="width: 100px;height: 100px;background: red" th:if="${age>25}">
我是小红
</div>
<div style="width: 100px;height: 100px;background: blue" th:if="${age<=25}">
我是小蓝
</div>
补充运算符:
gt: great than(大于) > ge: great equal(大于等于) >= eq: equal(等于) == lt: less than(小于) < le: less equal(小于等于) <= ne: not equal(不等于) !=
DemoControlleer
package com.study.controller;
import com.study.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* @ClassName DemoController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/13 20:36
* @Version 1.0
*/
@Controller
@RequestMapping("demo")
public class DemoController {
@RequestMapping("demo")
//model底层封装的也是request作用域
public String demo(HttpServletRequest request, Model model, HttpSession session){
System.out.println("demo ok!");
/**
* 5.向session作用域存储数据
*/
session.setAttribute("username","猪猪侠");
return "demo";
}
}
demo.html
<h2>5.获取session作用域数据</h2>
<span th:text="${session.username}"></span>

# 总结
- 1.使用 th:text="${属性名}" 获取对应数据,获取数据时会将对应标签中数据清空,因此最好是空标签
- 2.使用 th:utext="${属性名}" 获取对应的数据,可以将数据中html先解析在渲染到页面
- 3.使用 th:value="${属性名}" 获取数据直接作为表单元素value属性
使用thymeleaf模板时项目中的静态资源默认放在resources路径下的static目录中
demo.css
h2{
background: yellow;
}
demo.js
function test() {
alert('test');
}
demo.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>用来测试Thymeleaf语法</title>
<!--th:href="@{/}",其中,@{/}用来获取应用名称-->
<!--引入css资源-->
<link rel="stylesheet" th:href="@{/demo.css}">
<!--引入js资源-->
<script th:src="@{/demo.js}"></script>
<script>
test();
/**
* 通过js代码获取应用名:
* 通过Thymeleaf语法获取项目名,使用Thymeleaf内联表达式 [[thymeleaf]]
*/
let contentPath = "[[@{/}]]";
console.log("项目名",contentPath);
</script>
</head>
<body>
<h1>测试Thymeleaf语法基本使用</h1>
<h2>1.获取单个数据</h2>
<!--
th:text="${属性名}"获取request作用域数据:直接将获取到的数据以文本形式渲染到页面中
th:utext="${属性名}"获取request作用域数据:先将获取到的数据解析成html标签,再以文本形式渲染到页面中
-->
String类型数据:<span th:text="${name}"/><br>
Integer类型数据:<span th:text="${age}"/><br>
超链接:<span th:utext="${content}"/><br>
输入框:<br>
<input type="text" name="username" th:value="${name}"><br>
<input type="text" name="age" th:value="${age}">
<h2>2.获取对象类型数据</h2>
user.id:<span th:text="${user.id}"/><br>
user.name:<span th:text="${user.name}"/><br>
user.salary:<span th:text="${user.salary}"/><br>
<!--格式化日期:${#dates.format(格式化值,'格式化的格式')}},其中,dates.format为内置函数-->
user.birthday:<span th:text="${#dates.format(user.birthday,'yyyy-MM-dd HH:mm:ss')}"/>
<h2>3.获取集合类型数据</h2>
<ul>
<!--遍历数据:th:each="变量(current_element当前遍历元素),变量(state遍历状态对象):集合"-->
<li th:each="user,state:${users}">
state count: <span th:text="${state.count}"></span>
state odd: <span th:text="${state.odd}"></span>
state even: <span th:text="${state.even}"></span>
state size: <span th:text="${state.size}"></span>
id: <span th:text="${user.id}"></span>
name: <span th:text="${user.name}"></span>
salary: <span th:text="${user.salary}"></span>
birthday: <span th:text="${#dates.format(user.birthday,'yyyy年MM月dd日')}"></span>
</li>
</ul>
<h2>4.有条件的展示数据</h2>
<!-- th:if="${age>=25}" 作用:有条件的显示数据-->
<div style="width: 100px;height: 100px;background: red" th:if="${age>25}">
我是小红
</div>
<div style="width: 100px;height: 100px;background: blue" th:if="${age<=25}">
我是小蓝
</div>
<h2>5.获取session作用域数据</h2>
<span th:text="${session.username}"></span>
</body>
</html>
或者
<link rel="stylesheet" th:href="@{/css/index.css}">
<script th:src="@{/js/jquery-min.js}"></script>
注意: @{/}代表通过thymeleaf语法动态获取应用名
在js代码中获取项目名:
<script>
const ctx = '[[@{/}]]';
</script>
注意:[[书写thymeleaf语法]],这里[[ ]]是thymeleaf内嵌表达式。
最终效果:


配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili
【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili
需求分析: 分析这个项目含有哪些功能模块 用户模块: 注册 登录 验证码 安全退出 真实用户 员工模块: 添加员工+上传头像 展示员工列表+展示员工头像 删除员工信息+删除员工头像 更新员工信息+更新员工头像 库表设计(概要设计): 1.分析系统有哪些表 2.分析表与表关系 3.确定表中字段(显性字段 隐性字段(业务字段)) 2张表 1.用户表 user id username realname password gender 2.员工表 employee id name salary birthday photo 创建一个库: ems-thymeleaf 详细设计: 省略 编码(环境搭建+业务代码开发) 1.创建一个springboot项目 项目名字: ems-thymeleaf 2.修改配置文件为 application.yml pom.xml 2.5.0 3.修改端口 8888 项目名: ems-thymeleaf 4.springboot整合thymeleaf使用 a.引入依赖:thymeleaf b.配置文件中指定thymeleaf相关配置 c.编写控制器测试 5.springboot整合mybatis a.引入依赖:mysql、druid、mybatis-springboot-stater b.配置文件中 6.导入项目页面 static 存放静态资源 templates 目录 存放模板文件 测试 上线部署 维护 发版 ====================================================================== 用户相关: 1.登录 2.注册 3.验证码 1.验证码工具类
新建spring Initializr项目,引入Spring Web,项目命名为ems-thymeleaf
pom.xml引入thymeleaf依赖
<!--引入Thymeleaf依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <version>2.7.0</version> </dependency>
修改application.properties为application.yml,添加如下配置:
# 公共配置
server:
port: 8888
servlet:
context-path: /ems-thymeleaf
# Thymeleaf配置
spring:
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
新建demo.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>测试Thymeleaf</title>
</head>
<body>
<h1>测试Thymeleaf</h1>
<h4>获取数据:<span th:text="${msg}"></span></h4>
</body>
</html>
DemoController
package com.study.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @ClassName DemoController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 9:45
* @Version 1.0
*/
@Controller
@RequestMapping("demo")
public class DemoController {
private static final Logger log = LoggerFactory.getLogger(DemoController.class);
@RequestMapping("demo")
public String demo(Model model){
log.debug("demo ok");
model.addAttribute("msg","hello,Thymeleaf!");
return "demo";
}
}

pom.xml引入依赖:mysql、druid、mybatis-spring-boot-starter
<!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.4</version> </dependency> <!--mybatis-spring-boot-starter--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.0</version> </dependency>
application.yml引入配置
# 公共配置
server:
port: 8888
servlet:
context-path: /ems-thymeleaf
# Thymeleaf配置
spring:
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
# 配置数据源
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ems-thymeleaf?characterEncoding=UTF-8
username: root
password: 123456
# 配置mybatis
mybatis:
mapper-locations: classpath:com/study/mapper/*.xml
type-aliases-package: com.study.entity
# 配置日志
logging:
level:
root: info
com.study: debug
启动类添加注解扫描
package com.study;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.study.dao")
public class EmsThymeleafApplication {
public static void main(String[] args) {
SpringApplication.run(EmsThymeleafApplication.class, args);
}
}
重新启动一下项目,运行不报错即可。
在static目录下导入css、img、js等静态资源,导入之后Rebuild一下项目

新建MVC配置类:不用单独开发controller来访问html页面
package com.study.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @ClassName MvcConfig
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 10:35
* @Version 1.0
*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
//通过在这里面配置,不需要再为每一个访问thymeleaf模板页面单独开发一个controller请求了
public void addViewControllers(ViewControllerRegistry registry) {
//ViewController: 请求路径,ViewName: 跳转视图
registry.addViewController("login").setViewName("login");
registry.addViewController("register").setViewName("regist");//注意与HTML页面对应
}
}
启动项目,访问页面:
(1)注册页面:http://localhost:8888/ems-thymeleaf/register
(2)登录页面:http://localhost:8888/ems-thymeleaf/login
配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili
验证码工具类
package com.study.utils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Random;
/**
*@创建人 cx
*@创建时间 2018/11/27 17:36
*@描述 验证码生成
*/
public class VerifyCodeUtils{
//使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
private static Random random = new Random();
/**
* 使用系统默认字符源生成验证码
* @param verifySize 验证码长度
* @return
*/
public static String generateVerifyCode(int verifySize){
return generateVerifyCode(verifySize, VERIFY_CODES);
}
/**
* 使用指定源生成验证码
* @param verifySize 验证码长度
* @param sources 验证码字符源
* @return
*/
public static String generateVerifyCode(int verifySize, String sources){
if(sources == null || sources.length() == 0){
sources = VERIFY_CODES;
}
int codesLen = sources.length();
Random rand = new Random(System.currentTimeMillis());
StringBuilder verifyCode = new StringBuilder(verifySize);
for(int i = 0; i < verifySize; i++){
verifyCode.append(sources.charAt(rand.nextInt(codesLen-1)));
}
return verifyCode.toString();
}
/**
* 生成随机验证码文件,并返回验证码值
* @param w
* @param h
* @param outputFile
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, File outputFile, int verifySize) throws IOException{
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, outputFile, verifyCode);
return verifyCode;
}
/**
* 输出随机验证码图片流,并返回验证码值
* @param w
* @param h
* @param os
* @param verifySize
* @return
* @throws IOException
*/
public static String outputVerifyImage(int w, int h, OutputStream os, int verifySize) throws IOException{
String verifyCode = generateVerifyCode(verifySize);
outputImage(w, h, os, verifyCode);
return verifyCode;
}
/**
* 生成指定验证码图像文件
* @param w
* @param h
* @param outputFile
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, File outputFile, String code) throws IOException{
if(outputFile == null){
return;
}
File dir = outputFile.getParentFile();
if(!dir.exists()){
dir.mkdirs();
}
try{
outputFile.createNewFile();
FileOutputStream fos = new FileOutputStream(outputFile);
outputImage(w, h, fos, code);
fos.close();
} catch(IOException e){
throw e;
}
}
/**
* 输出指定验证码图片流
* @param w
* @param h
* @param os
* @param code
* @throws IOException
*/
public static void outputImage(int w, int h, OutputStream os, String code) throws IOException{
int verifySize = code.length();
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Random rand = new Random();
Graphics2D g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
Color[] colors = new Color[5];
Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN,
Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE,
Color.PINK, Color.YELLOW };
float[] fractions = new float[colors.length];
for(int i = 0; i < colors.length; i++){
colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
fractions[i] = rand.nextFloat();
}
Arrays.sort(fractions);
g2.setColor(Color.GRAY);// 设置边框色
g2.fillRect(0, 0, w, h);
Color c = getRandColor(200, 250);
g2.setColor(c);// 设置背景色
g2.fillRect(0, 2, w, h-4);
//绘制干扰线
Random random = new Random();
g2.setColor(getRandColor(160, 200));// 设置线条的颜色
for (int i = 0; i < 20; i++) {
int x = random.nextInt(w - 1);
int y = random.nextInt(h - 1);
int xl = random.nextInt(6) + 1;
int yl = random.nextInt(12) + 1;
g2.drawLine(x, y, x + xl + 40, y + yl + 20);
}
// 添加噪点
float yawpRate = 0.05f;// 噪声率
int area = (int) (yawpRate * w * h);
for (int i = 0; i < area; i++) {
int x = random.nextInt(w);
int y = random.nextInt(h);
int rgb = getRandomIntColor();
image.setRGB(x, y, rgb);
}
shear(g2, w, h, c);// 使图片扭曲
g2.setColor(getRandColor(100, 160));
int fontSize = h-4;
Font font = new Font("Algerian", Font.ITALIC, fontSize);
g2.setFont(font);
char[] chars = code.toCharArray();
for(int i = 0; i < verifySize; i++){
AffineTransform affine = new AffineTransform();
affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize/2, h/2);
g2.setTransform(affine);
g2.drawChars(chars, i, 1, ((w-10) / verifySize) * i + 5, h/2 + fontSize/2 - 10);
}
g2.dispose();
ImageIO.write(image, "jpg", os);
}
private static Color getRandColor(int fc, int bc) {
if (fc > 255)
fc = 255;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
private static int getRandomIntColor() {
int[] rgb = getRandomRgb();
int color = 0;
for (int c : rgb) {
color = color << 8;
color = color | c;
}
return color;
}
private static int[] getRandomRgb() {
int[] rgb = new int[3];
for (int i = 0; i < 3; i++) {
rgb[i] = random.nextInt(255);
}
return rgb;
}
private static void shear(Graphics g, int w1, int h1, Color color) {
shearX(g, w1, h1, color);
shearY(g, w1, h1, color);
}
private static void shearX(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(2);
boolean borderGap = true;
int frames = 1;
int phase = random.nextInt(2);
for (int i = 0; i < h1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(0, i, w1, 1, (int) d, 0);
if (borderGap) {
g.setColor(color);
g.drawLine((int) d, i, 0, i);
g.drawLine((int) d + w1, i, w1, i);
}
}
}
private static void shearY(Graphics g, int w1, int h1, Color color) {
int period = random.nextInt(40) + 10; // 50;
boolean borderGap = true;
int frames = 20;
int phase = 7;
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (6.2831853071795862D * (double) phase)
/ (double) frames);
g.copyArea(i, 0, 1, h1, 0, (int) d);
if (borderGap) {
g.setColor(color);
g.drawLine(i, (int) d, i, 0);
g.drawLine(i, (int) d + h1, i, h1);
}
}
}
}
添加控制器UserController
package com.study.controller;
import com.study.utils.VerifyCodeUtils;
import com.sun.deploy.net.HttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @ClassName UserController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 11:53
* @Version 1.0
*/
@Controller
@RequestMapping("user")
public class UserController {
/**
* @MethodName generateImageCode
* @Description 生成图片验证码
* @param: session
* @param: response
* @Author Jiangnan Cui
* @Date 2022/6/27 12:08
*/
@RequestMapping("generateImageCode")
public void generateImageCode(HttpSession session, HttpServletResponse response) throws IOException {
//1.生成4位随机数
String code = VerifyCodeUtils.generateVerifyCode(4);
//2.保存到session作用域
session.setAttribute("code",code);
//3.设置响应类型
response.setContentType("image/png");
//4.获得输出流
ServletOutputStream sos = response.getOutputStream();
//5.根据随机数生成图片
VerifyCodeUtils.outputImage(220,60,sos,code);
}
}
register.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>regist</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />
</head>
<body>
<div id="wrap">
<div id="top_content">
<div id="header">
<div id="rightheader">
<p>
2009/11/20
<br />
</p>
</div>
<div id="topheader">
<h1 id="title">
<a href="#">main</a>
</h1>
</div>
<div id="navigation">
</div>
</div>
<div id="content">
<p id="whereami">
</p>
<h1>
注册
</h1>
<form th:action="@{/user/register}" method="post">
<table cellpadding="0" cellspacing="0" border="0"
class="form_table">
<tr>
<td valign="middle" align="right">
用户名:
</td>
<td valign="middle" align="left">
<input type="text" class="inputgri" name="username" />
</td>
</tr>
<tr>
<td valign="middle" align="right">
真实姓名:
</td>
<td valign="middle" align="left">
<input type="text" class="inputgri" name="realname" />
</td>
</tr>
<tr>
<td valign="middle" align="right">
密码:
</td>
<td valign="middle" align="left">
<input type="password" class="inputgri" name="password" />
</td>
</tr>
<tr>
<td valign="middle" align="right">
性别:
</td>
<td valign="middle" align="left">
男
<input type="radio" class="inputgri" name="gender" value="1" checked="checked"/>
女
<input type="radio" class="inputgri" name="gender" value="0"/>
</td>
</tr>
<tr>
<td valign="middle" align="right">
验证码:
<img id="num" th:src="@{/user/generateImageCode}" />
<a href="javascript:;" οnclick="changeImageCode()">换一张</a>
<script>
function changeImageCode(){
document.getElementById('num').src = '[[@{/user/generateImageCode}]]?'+(new Date()).getTime()
}
</script>
</td>
<td valign="middle" align="left">
<input type="text" class="inputgri" name="code" />
</td>
</tr>
</table>
<p>
<input type="submit" class="button" value="立即注册 »" />
<a href="login.html">已有账号,返回登录</a>
</p>
</form>
</div>
</div>
<div id="footer">
<div id="footer_bg">
ABC@126.com
</div>
</div>
</div>
</body>
</html>
测试路径
(1)http://localhost:8888/ems-thymeleaf/user/generateImageCode

(2)http://localhost:8888/ems-thymeleaf/register

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili
创建数据库ems-thymeleaf、表user
create database ems-thymeleaf if not exists;
user ems-thymeleaf;
create tabble user if not exists(
id int(20) not null auto_increment comment '用户ID',
username varchar(100) not nulll comment '用户名',
realname varchar(100) comment '真实姓名',
password varchar(100) comment '密码',
gender boolean comment '性别',
primary key(id)
)engine=innodb charset=utf8;
新建实体类User
package com.study.entity;
/**
* @ClassName User
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 15:49
* @Version 1.0
*/
public class User {
private Integer id;
private String username;
private String realname;
private String password;
private Boolean gender;
public User() {
}
public User(Integer id, String username, String realname, String password, Boolean gender) {
this.id = id;
this.username = username;
this.realname = realname;
this.password = password;
this.gender = gender;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", realname='" + realname + '\'' +
", password='" + password + '\'' +
", gender=" + gender +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getRealname() {
return realname;
}
public void setRealname(String realname) {
this.realname = realname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Boolean getGender() {
return gender;
}
public void setGender(Boolean gender) {
this.gender = gender;
}
}
创建UserDAO
package com.study.dao;
import com.study.entity.User;
/**
* @ClassName UserDAO
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 16:02
* @Version 1.0
*/
public interface UserDAO {
/**
* @MethodName findByUserName
* @Description 根据用户名查找用户
* @param: username
* @return: com.study.entity.User
* @Author Jiangnan Cui
* @Date 2022/6/27 16:03
*/
User findByUserName(String username);
/**
* @MethodName register
* @Description 用户注册
* @param: user
* @Author Jiangnan Cui
* @Date 2022/6/27 16:03
*/
void register(User user);
}
创建UserDAOMapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.study.dao.UserDAO">
<!--findByUserName-->
<select id="findByUserName" parameterType="String" resultType="User">
select
id,username,realname,password,gender
from `user`
where username=#{username}
</select>
<!--register-->
<insert id="register" parameterType="User" useGeneratedKeys="true" keyProperty="id">
insert into `user` values(#{id},#{username},#{realname},#{password},#{gender})
</insert>
</mapper>
创建UserService
package com.study.service;
import com.study.entity.User;
/**
* @ClassName UserService
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 15:48
* @Version 1.0
*/
public interface UserService {
/**
* @MethodName register
* @Description 用户注册
* @param: user
* @Author Jiangnan Cui
* @Date 2022/6/27 15:50
*/
void register(User user);
}
创建UserServiceImpl
package com.study.service;
import com.study.dao.UserDAO;
import com.study.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;
import java.nio.charset.StandardCharsets;
/**
* @ClassName UserServiceImpl
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 16:14
* @Version 1.0
*/
@Service
@Transactional
public class UserServiceImpl implements UserService{
//业务逻辑层调用数据访问层
private UserDAO userDAO;
@Autowired
public UserServiceImpl(UserDAO userDAO) {
this.userDAO = userDAO;
}
/**
* @MethodName register
* @Description
* @param: user
* @Author Jiangnan Cui
* @Date 2022/6/27 16:22
*/
@Override
public void register(User user) {
//1.根据用户名从数据库中查询是否存在已经注册的用户
User userDB = userDAO.findByUserName(user.getUsername());
//2.判断该用户是否存在
if(!ObjectUtils.isEmpty(userDB))
throw new RuntimeException("当前用户已被注册!");//不为空时抛出异常
//3.为空时表明用户不存在,继续注册用户
//对明文密码进行加密:相同字符串多次使用md5加密后结果一致
String newPassword = DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8));
user.setPassword(newPassword);
userDAO.register(user);
}
}
新建UserController
package com.study.controller;
import com.study.entity.User;
import com.study.service.UserService;
import com.study.utils.VerifyCodeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @ClassName UserController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 11:53
* @Version 1.0
*/
@Controller
@RequestMapping("user")
public class UserController {
//新建日志对象
private static final Logger log = LoggerFactory.getLogger(UserController.class);
/**
* @MethodName generateImageCode
* @Description 生成图片验证码
* @param: session
* @param: response
* @Author Jiangnan Cui
* @Date 2022/6/27 12:08
*/
@RequestMapping("generateImageCode")
public void generateImageCode(HttpSession session, HttpServletResponse response) throws IOException {
//1.生成4位随机数
String code = VerifyCodeUtils.generateVerifyCode(4);
//2.保存到session作用域
session.setAttribute("code",code);
//3.设置响应类型
response.setContentType("image/png");
//4.获得输出流
ServletOutputStream sos = response.getOutputStream();
//5.根据随机数生成图片
VerifyCodeUtils.outputImage(220,60,sos,code);
}
private UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
/**
* @MethodName register
* @Description 用户注册
* @param: user
* @param: code
* @param: session
* @return: java.lang.String
* @Author Jiangnan Cui
* @Date 2022/6/27 15:57
*/
@RequestMapping("register")
public String register(User user,String code,HttpSession session){
log.debug("用户名:{},真实姓名:{},密码:{},性别:{}",
user.getUsername(),user.getRealname(),user.getPassword(),user.getGender());
log.debug("用户输入的验证码: {}",code);
try {
//1.判断用户输入验证码和session中的验证码是否一致
String sessionCode = session.getAttribute("code").toString();
if(!sessionCode.equalsIgnoreCase(code))
throw new RuntimeException("验证码输入错误!");
//2.注册用户
userService.register(user);
} catch (RuntimeException e) {
e.printStackTrace();
return "redirect:/register";//注册失败回到注册
}
return "redirect:/login";//注册成功转到登录
}
}
访问路径:http://localhost:8888/ems-thymeleaf/register,进行注册,成功跳转到登录页面,失败回到注册页面!
配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili
在UserService添加登录方法
/** * @MethodName login * @Description 用户登录 * @param: username * @param: password * @return: com.study.entity.User * @Author Jiangnan Cui * @Date 2022/6/27 17:02 */ User login(String username,String password);
在UserServiceImpl实现登录方法
/**
* @MethodName login
* @Description 用户登录
* @param: username
* @param: password
* @return: com.study.entity.User
* @Author Jiangnan Cui
* @Date 2022/6/27 17:03
*/
@Override
public User login(String username, String password) {
//1.根据用户名查询用户
User user = userDAO.findByUserName(username);
//2.判断用户是否存在,存在执行登录;不存在,抛出异常
if(ObjectUtils.isEmpty(user))
throw new RuntimeException("用户名不存在!");
//3.在用户存在的前提下,比较密码是否正确,正确执行登录;不正确,抛出异常
//密码加密
String passwordSecret = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));
if(!user.getPassword().equals(passwordSecret))
throw new RuntimeException("密码错误!");
return user;
}
UserController添加登录方法
/**
* @MethodName login
* @Description 用户登录
* @param: username
* @param: password
* @param: session
* @return: java.lang.String
* @Author Jiangnan Cui
* @Date 2022/6/27 17:11
*/
@RequestMapping("login")
public String login(String username,String password,HttpSession session){
log.debug("本次登录的用户名为:{}",username);
log.debug("本次登录的密码为:{}",password);
try {
//1.调用业务逻辑层进行登录
User user = userService.login(username, password);
//2.保存用户信息供页面调用
session.setAttribute("user",user);
} catch (Exception e) {
e.printStackTrace();
return "redirect:/login";//登录失败回到登录页面
}
return "redirect:/employee/lists";//登录成功,跳转到查询所有员工信息控制器路径
}
添加EmpployeeController
package com.study.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @ClassName EmployeeController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 17:15
* @Version 1.0
*/
@Controller
@RequestMapping("employee")
public class EmployeeController {
private static final Logger log = LoggerFactory.getLogger(EmployeeController.class);
@RequestMapping("lists")
public String list(Model model){
log.debug("查询所有员工信息");
return "emplist";
}
}
login.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>login</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css"
href="css/style.css" />
</head>
<body>
<div id="wrap">
<div id="top_content">
<div id="header">
<div id="rightheader">
<p>
2009/11/20
<br />
</p>
</div>
<div id="topheader">
<h1 id="title">
<a href="#">main</a>
</h1>
</div>
<div id="navigation">
</div>
</div>
<div id="content">
<p id="whereami">
</p>
<h1>
欢迎进入,请登录!
</h1>
<form th:action="@{/user/login}" method="post">
<table cellpadding="0" cellspacing="0" border="0"
class="form_table">
<tr>
<td valign="middle" align="right">
用户名:
</td>
<td valign="middle" align="left">
<input type="text" class="inputgri" name="username" />
</td>
</tr>
<tr>
<td valign="middle" align="right">
密码:
</td>
<td valign="middle" align="left">
<input type="password" class="inputgri" name="password" />
</td>
</tr>
</table>
<p>
<input type="submit" class="button" value="点我登录 »" />
<a href="regist.html">还没有账号,立即注册</a>
</p>
</form>
</div>
</div>
<div id="footer">
<div id="footer_bg">
ABC@126.com
</div>
</div>
</div>
</body>
</html>
emplists.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>emplist</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" th:href="@{/css/style.css}" />
</head>
<body>
<div id="wrap">
<div id="top_content">
<div id="header">
<div id="rightheader">
<p>
2009/11/20
<br />
<a th:if="${session.user!=null}" th:href="@{/user/logout}">安全退出</a>
<a th:if="${session.user==null}" th:href="@{/login}">点我登录</a>
</p>
</div>
<div id="topheader">
<h1 id="title">
<a href="#">main</a>
</h1>
</div>
<div id="navigation">
</div>
</div>
<div id="content">
<p id="whereami">
</p>
<h1>
欢迎 <span th:if="${session.user!=null}" th:text="${session.user.username}"></span>
<span th:if="${session.user==null}" >游客</span>!
</h1>
<table class="table">
<tr class="table_header">
<td>
编号
</td>
<td>
姓名
</td>
<td>
头像
</td>
<td>
工资
</td>
<td>
生日
</td>
<td>
操作
</td>
</tr>
<tr th:each="employee,state:${employeeList}" th:class="${state.odd?'row1':'row2'}">
<td>
<span th:text="${employee.id}"></span>
</td>
<td>
<span th:text="${employee.name}"></span>
</td>
<td>
<img th:src="@{/}+${employee.photo}" width="60">
</td>
<td>
<span th:text="${employee.salary}"></span>
</td>
<td>
<span th:text="${#dates.format(employee.birthday,'yyyy/MM/dd')}"></span>
</td>
<td>
<a href="javascript:;" th:οnclick="'deleteEmployee('+${employee.id}+')'">删除</a>
<!-- <a th:href="@{/employee/detail?id=}+${employee.id}+'&name='+${employee.name}">更新</a>-->
<!-- <a th:href="@{/employee/detail(id=${employee.id},name=${employee.name})}">更新</a>-->
<a th:href="@{/employee/detail(id=${employee.id})}">更新</a>
</td>
</tr>
<script>
function deleteEmployee(id){
console.log(id);
if(window.confirm('确定要删除这条记录吗?')){
location.href='[[@{/employee/delete?id=}]]'+id;
}
}
</script>
</table>
<p>
<input type="button" class="button" value="添加" οnclick="addEmp()"/>
<script>
function addEmp(){
location.href = '[[@{/addEmp}]]';
}
</script>
</p>
</div>
</div>
<div id="footer">
<div id="footer_bg">
ABC@126.com
</div>
</div>
</div>
</body>
</html>
测试路径:http://localhost:8888/ems-thymeleaf/login,登录成功跳转到员工列表页面,登录失败回到登录页面。

配套视频:【编程不良人】2021年SpringBoot最新最全教程_哔哩哔哩_bilibili
创建employee表
create table employee if not exists(
id int(20) not null auto_increment comment '员工ID',
name varchar(100) not null comment '姓名',
salary double not null comment '工资',
birthday datetime not null comment '生日',
photo carchar(100) not null comment '头像',
primary key(id)
)engine=innodb charset=utf8;
新建实体类Employee
package com.study.entity;
import java.util.Date;
/**
* @ClassName Employee
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 18:11
* @Version 1.0
*/
public class Employee {
private Integer id;
private String name;
private Double salary;
private Date birthday;
private String photo;
public Employee() {
}
public Employee(Integer id, String name, Double salary, Date birthday, String photo) {
this.id = id;
this.name = name;
this.salary = salary;
this.birthday = birthday;
this.photo = photo;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", salary=" + salary +
", birthday=" + birthday +
", photo='" + photo + '\'' +
'}';
}
}
新建EmployeeDAO
package com.study.dao;
import com.study.entity.Employee;
import java.util.List;
/**
* @ClassName EmployeeDAO
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 18:23
* @Version 1.0
*/
public interface EmployeeDAO {
/**
* @MethodName lists
* @Description 员工列表
* @return: java.util.List<com.study.entity.Employee>
* @Author Jiangnan Cui
* @Date 2022/6/27 18:24
*/
List<Employee> lists();
}
新建EmployeeDAOMapper
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.study.dao.EmployeeDAO"> <!--lists--> <select id="lists" resultType="Employee"> select id,name,salary,birthday,photo from employee </select> </mapper>
新建EmployeeService
package com.study.service;
import com.study.entity.Employee;
import java.util.List;
/**
* @ClassName EmployeeService
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 18:26
* @Version 1.0
*/
public interface EmployeeService {
/**
* @MethodName lists
* @Description 员工列表
* @return: java.util.List<com.study.entity.Employee>
* @Author Jiangnan Cui
* @Date 2022/6/27 18:27
*/
List<Employee> lists();
}
新建EmployeeServiceImpl
package com.study.service;
import com.study.dao.EmployeeDAO;
import com.study.entity.Employee;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @ClassName EmployeeServiceImpl
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 18:27
* @Version 1.0
*/
@Service
@Transactional
public class EmployeeServiceImpl implements EmployeeService{
//业务逻辑层调用数据访问层
private EmployeeDAO employeeDAO;
@Autowired
public EmployeeServiceImpl(EmployeeDAO employeeDAO) {
this.employeeDAO = employeeDAO;
}
/**
* @MethodName lists
* @Description 员工列表
* @return: java.util.List<com.study.entity.Employee>
* @Author Jiangnan Cui
* @Date 2022/6/27 18:29
*/
@Override
public List<Employee> lists() {
return employeeDAO.lists();
}
}
完善EmployeeController
package com.study.controller;
import com.study.entity.Employee;
import com.study.service.EmployeeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* @ClassName EmployeeController
* @Description TODO
* @Author Jiangnan Cui
* @Date 2022/6/27 17:15
* @Version 1.0
*/
@Controller
@RequestMapping("employee")
public class EmployeeController {
//日志对象
private static final Logger log = LoggerFactory.getLogger(EmployeeController.class);
//控制层调用业务逻辑层
private EmployeeService employeeService;
@Autowired
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
/**
* @MethodName list
* @Description 员工列表
* @param: model
* @return: java.lang.String
* @Author Jiangnan Cui
* @Date 2022/6/27 18:04
*/
@RequestMapping("lists")
public String list(Model model){
log.debug("查询所有员工信息");
List<Employee> employeeList = employeeService.lists();
model.addAttribute("employeeList",employeeList);
return "emplist";
}
}

完善EmployeDAO
/** * @MethodName addEmp * @Description 保存员工信息 * @param: employee * @Author Jiangnan Cui * @Date 2022/6/27 20:11 */ void addEmp(Employee employee);
完善EmpDAOMapper
<!--addEmp-->
<insert id="addEmp" parameterType="Employee" useGeneratedKeys="true" keyProperty="id">
insert into employee values(#{id},#{name},#{salary},#{birthday},#{photo})
</insert>
完善EmployeeService
/** * @MethodName addEmp * @Description * @param: employee * @Author Jiangnan Cui * @Date 2022/6/27 20:12 */ void addEmp(Employee employee);
完善EmpEmployeeServiceImpl
/**
* @MethodName addEmp
* @Description 添加员工信息
* @param: employee
* @Author Jiangnan Cui
* @Date 2022/6/27 20:13
*/
@Override
public void addEmp(Employee employee) {
employeeDAO.addEmp(employee);
}
EmployeeController
//定义文件路径
@Value("${photo.file.dir}")
private String realpath;
/**
* @MethodName uploadPhoto
* @Description 上传头像
* @param: img
* @param: originalFileName
* @return: java.lang.String
* @Author Jiangnan Cui
* @Date 2022/6/27 20:23
*/
private String uploadPhoto(MultipartFile img,String originalFileName) throws IOException {
String fileNamePrefix = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
String fileNameSuffix = originalFileName.substring(originalFileName.lastIndexOf("."));
String newFileName = fileNamePrefix + fileNameSuffix;
img.transferTo(new File(realpath,newFileName));
return newFileName;
}
/**
* @MethodName addEmp
* @Description 添加员工信息
* @param: employee
* @param: img
* @return: java.lang.String
* @Author Jiangnan Cui
* @Date 2022/6/27 20:15
*/
@RequestMapping("addEmp")
public String addEmp(Employee employee, MultipartFile img) throws IOException {
log.debug("姓名:{},工资:{},生日:{}",employee.getName(),employee.getSalary(),employee.getBirthday());
//获得图片原始文件名
String originalFilename = img.getOriginalFilename();
log.debug("头像名称:{}",originalFilename);
log.debug("头像大小:{}",img.getSize());
log.debug("上传路径:{}",realpath);
//1.处理头像的上传
String newFileName = uploadPhoto(img, originalFilename);
//2.保存员工信息
employee.setPhoto(newFileName);//保存头衔名字
employeeService.addEmp(employee);
return "redirect:/employee/lists";//保存成功跳转到员工列表
}
application.yml添加文件上传配置
# 公共配置
server:
port: 8888
servlet:
context-path: /ems-thymeleaf
# Thymeleaf配置
spring:
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
# 配置数据源
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/ems-thymeleaf?characterEncoding=UTF-8
username: root
password: 123456
# 暴露哪些资源可以通过项目名直接访问
web:
resources:
static-locations: classpath:/static/,file:${photo.file.dir}
# 配置mybatis
mybatis:
mapper-locations: classpath:com/study/mapper/*.xml
type-aliases-package: com.study.entity
# 配置日志
logging:
level:
root: info
com.study: debug
# 指定文件上传位置
photo:
file:
dir: D:\Software_Development\IDEA_code\SpringBoot\ems-thymeleaf\photos
完善MvcConfig
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
//通过在这里面配置,不需要再为每一个访问thymeleaf模板页面单独开发一个controller请求了
public void addViewControllers(ViewControllerRegistry registry) {
//ViewController: 请求路径,ViewName: 跳转视图
registry.addViewController("login").setViewName("login");
registry.addViewController("register").setViewName("regist");
registry.addViewController("addEmp").setViewName("addEmp");
}
}
addEmp.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html xmlns:th="http://www.thymealf.org">
<head>
<title>添加员工信息</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css"
href="css/style.css" />
</head>
<body>
<div id="wrap">
<div id="top_content">
<div id="header">
<div id="rightheader">
<p>
2009/11/20
<br />
</p>
</div>
<div id="topheader">
<h1 id="title">
<a href="#">main</a>
</h1>
</div>
<div id="navigation">
</div>
</div>
<div id="content">
<p id="whereami">
</p>
<h1>
添加员工信息:
</h1>
<form th:action="@{/employee/addEmp}" method="post" enctype="multipart/form-data">
<table cellpadding="0" cellspacing="0" border="0"
class="form_table">
<tr>
<td valign="middle" align="right">
姓名:
</td>
<td valign="middle" align="left">
<input type="text" class="inputgri" name="name" />
</td>
</tr>
<tr>
<td valign="middle" align="right">
头像:
</td>
<td valign="middle" align="left">
<input type="file" width="" name="img" />
</td>
</tr>
<tr>
<td valign="middle" align="right">
工资:
</td>
<td valign="middle" align="left">
<input type="text" class="inputgri" name="salary" />
</td>
</tr>
<tr>
<td valign="middle" align="right">
生日:
</td>
<td valign="middle" align="left">
<input type="text" class="inputgri" name="birthday" />
</td>
</tr>
</table>
<p>
<input type="submit" class="button" value="确认添加" />
<input type="submit" class="button" value="返回列表" />
</p>
</form>
</div>
</div>
<div id="footer">
<div id="footer_bg">
ABC@126.com
</div>
</div>
</div>
</body>
</html>
访问路径:http://localhost:8888/ems-thymeleaf/employee/lists,添加员工信息



待完善