1.创建SpringBoot项目,引入依赖
pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.5.4
com.example
ems-thymeleaf
0.0.1-SNAPSHOT
ems-thymeleaf
ems-thymeleaf
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-thymeleaf
2.5.1
mysql
mysql-connector-java
8.0.26
com.alibaba
druid
1.2.6
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.2.0
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
2.修改配置文件application.yml
server:
port: 8989
servlet:
context-path: /ems
spring:
thymeleaf:
cache: false
suffix: .html
prefix: classpath:/templates/
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/mydata?useUnicode=true&characterEncoding=UTF-8
username: root
password: 835081
web:
#暴露哪些资源可以通过项目名访问
resources:
static-locations: classpath:/static/,file:${img.file.dir}
logging:
level:
root: info
com.example.emsthymeleaf: debug
mybatis:
mapper-locations: classpath:/mapper/*.xml
type-aliases-package: com.example.emsthymeleaf.entity
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 上传文件路径
img:
file:
dir: D:\develop\javademo\baizhidemo\ems-thymeleaf\file
3.创建Config文件,将对html文件的访问对应到Controller
这样做的目的是为了简化访问thymeleaf的html文件,不必为每个html文件单独创建controller请求
package com.example.emsthymeleaf.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
//不用再为每一个thymeleaf模板单独开发一个controller请求了
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//viewController:请求路径,viewName:跳转视图
registry.addViewController("login").setViewName("login");
registry.addViewController("regist").setViewName("regist");
}
}
4.设置随机图形验证码
- 引入验证码生成工具VerifyCodeUtils
- 在controller中创建生成验证码实例
package com.example.emsthymeleaf.controller;
import com.example.emsthymeleaf.utils.VerifyCodeUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
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;
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/generateImageCode")
public void generateImageCode(HttpServletResponse response, HttpSession session) throws IOException {
//生成随机数
String code = VerifyCodeUtils.generateVerifyCode(4);
//存入session
session.setAttribute("code",code);
//根据随机数生成随即图片
response.setContentType("image/png");
ServletOutputStream outputStream = response.getOutputStream();
VerifyCodeUtils.outputImage(220,60,outputStream,code);
}
}
- 在thymeleaf的html文件中设置访问随机验证码
验证码:
换一张
5.用户注册
- 引入lombok
org.projectlombok
lombok
1.18.20
- 创建实体类User
package com.example.emsthymeleaf.entity;
import lombok.Data;
@Data
public class User {
private Integer id;
private String username;
private String realname;
private String password;
private boolean gender;
}
- controller
@PostMapping("/regist")
public String regist(User user, String code,HttpSession session) throws UnsupportedEncodingException {
log.debug("用户信息:" + user);
log.debug("验证码:" + code);
try {
userSerivce.regist(user,code,session);
}catch (Exception ex){
return "redirect:/regist?err=" + URLEncoder.encode(ex.getMessage(),"UTF-8");
}
return "redirect:/login";
}
- service
package com.example.emsthymeleaf.service;
import com.example.emsthymeleaf.entity.User;
import javax.servlet.http.HttpSession;
public interface UserSerivce {
void regist(User user, String code, HttpSession session);
}
- serviceImpl
package com.example.emsthymeleaf.service;
import com.example.emsthymeleaf.dao.UserDao;
import com.example.emsthymeleaf.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import javax.servlet.http.HttpSession;
import java.nio.charset.StandardCharsets;
@Service
@Transactional
public class UserServiceImpl implements UserSerivce {
private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
private UserDao userDao;
@Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void regist(User user, String code, HttpSession session) {
//判断用户输入的验证码和session中存储的验证码是否相同
log.debug("session code: {}",session.getAttribute("code"));
if (!code.equalsIgnoreCase(session.getAttribute("code").toString())) {
throw new RuntimeException("验证码错误!");
}
//判断用户名是否已注册过
if (userDao.getUserByUserName(user.getUsername()) != null) {
throw new RuntimeException("用户名已注册过了!");
}
//给密码加密
user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8)));
//将输入插入到数据表
userDao.save(user);
}
}
- dao
package com.example.emsthymeleaf.dao;
import com.example.emsthymeleaf.entity.User;
public interface UserDao {
void save(User user);
User getUserByUserName(String username);
}
- xml
insert into user values(#{id},#{username},#{realname},#{password},#{gender})
- 注册页面.html
注册
6. 用户登录和退出
6.1 用户登录
controller
@RequestMapping("/login")
public String login(String username, String password, HttpSession session) throws UnsupportedEncodingException {
try {
User user = userSerivce.login(username, password);
session.setAttribute("user", user);
} catch (Exception e) {
e.printStackTrace();
return "redirect:/login?err=" + URLEncoder.encode(e.getMessage(), "UTF-8");
}
return "redirect:/employee/list";
}
service
@Override
public User login(String username, String password) {
User user = userDao.getUserByUserName(username);
if (ObjectUtils.isEmpty(user)) throw new RuntimeException("用户不存在");
String newPassword = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));
if (!user.getPassword().equals(newPassword)) throw new RuntimeException(("密码输入错误"));
return user;
}
html
欢迎进入,请登录!
6.2 用户退出
controller
//用户退出
@RequestMapping("/logout")
public String logout( HttpSession session){
session.invalidate();
return "redirect:/login";
}
html
安全退出
7. 员工管理
7.1 添加员工
- 修改config文件,通过浏览器能够访问到addEmp.html页面
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
//不用再为每一个thymeleaf模板单独开发一个controller请求了
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//viewController:请求路径,viewName:跳转视图
registry.addViewController("login").setViewName("login");
registry.addViewController("regist").setViewName("regist");
registry.addViewController("addEmp").setViewName("addEmp");
}
}
- 添加员工的controller
package com.example.emsthymeleaf.controller;
import com.example.emsthymeleaf.entity.Employee;
import com.example.emsthymeleaf.service.EmployeeService;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
@Controller
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
private static final Logger log = LoggerFactory.getLogger(EmployeeController.class);
@Value("${img.file.dir}")
private String realPath;
@RequestMapping("/save")
public String save(Employee employee, MultipartFile img) throws IOException {
log.debug("employee: {}",employee);
log.debug("file name: {}", img.getOriginalFilename());
//创建新文件名
String newImgName = setNewImgName(img);
//将头像文件存储到文件夹
img.transferTo(new File(realPath,newImgName));
//存储新的文件名
employee.setPhoto(newImgName);
//存储员工信息
employeeService.save(employee);
return "redirect:/employee/list";
}
//生成新的文件名
private String setNewImgName(MultipartFile img) {
//前缀
String fileNamePrefix = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
//后缀
String fileNameSuffix = FilenameUtils.getExtension(img.getOriginalFilename());
//新文件名
String newImgName = fileNamePrefix + "." + fileNameSuffix;
return newImgName;
}
}
如何确定文件的上传路径
在application.yml中确定文件的上传路径
# 上传文件路径
img:
file:
dir: D:\develop\javademo\baizhidemo\ems-thymeleaf\file
在java文件中引用它
@Value("${img.file.dir}")
private String realPath;
serviceImpl
@Override
public void save(Employee employee) {
employeeDao.save(employee);
}
dao
void save(Employee employee);
dao.xml
insert into employee values (#{id},#{name},#{photo},#{salary},#{birthday})
html
7.2 员工列表
controller
@RequestMapping("list")
public String list(Model model) {
model.addAttribute("list", employeeService.list());
return "emplist";
}
serviceImpl
@Override
public List list() {
return employeeDao.list();
}
dao
List list();
dao.xml
html
thymeleaf需要注意的点
- 在标签中获取当前路径的静态文件:
,将路径和文件名连接起来
需要修改application.yml文件,暴露哪些资源可以通过项目名访问
resources: static-locations: classpath:/static/,file:${img.file.dir}
标签链接到带参数的地址:
更新
,在th中应该写为:更新
- 将标签中的链接改为响应click事件的html语句:
删除
7.3 编辑员工信息
7.3.1 根据id获取员工信息
controller
//根据id获取员工信息
@RequestMapping("details")
public String details(Integer id, Model model) {
log.debug("id:{}", id);
Employee employee = employeeService.findById(id);
model.addAttribute("employee", employee);
return "updateEmp";
}
service&serviceImpl
Employee findById(Integer id);
@Override
public Employee findById(Integer id) {
return employeeDao.findById(id);
}
dao
Employee findById(Integer id);
html显示编辑员工信息页面
注意两个隐藏类型的input,因为和标签的信息无法通过请求传递,所以这两个标签下面需要设置隐藏类型的input,用于传递属性值
7.3.2 更新员工信息
controller
//更新员工信息
@RequestMapping("update")
public String update(Employee employee, MultipartFile img){
log.debug("员工信息:{}",employee);
//判断是否更新了头像信息
if (!img.isEmpty()){
//更新头像信息
try {
String newImgName = uploadImg(img);
employee.setPhoto(newImgName);
} catch (IOException e) {
e.printStackTrace();
}
}
employeeService.update(employee);
return "redirect:/employee/list";
}
/**
* 存储上传的文件并生成新的文件名
* @param img
* @return 返回新的文件名
* @throws IOException
*/
private String uploadImg(MultipartFile img) throws IOException {
//前缀
String fileNamePrefix = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
//后缀
String fileNameSuffix = FilenameUtils.getExtension(img.getOriginalFilename());
//新文件名
String newImgName = fileNamePrefix + "." + fileNameSuffix;
//将头像文件存储到文件夹
img.transferTo(new File(realPath, newImgName));
return newImgName;
}
service&serviceImpl
void update(Employee employee);
@Override
public void update(Employee employee) {
employeeDao.update(employee);
}
dao
void update(Employee employee);
update employee set name=#{name},photo=#{photo},salary=#{salary},birthday=#{birthday} where id = #{id}
7.3.3 删除员工信息
controller
//删除员工信息
@RequestMapping("/delete")
public String delete(Integer id){
log.debug("id={}",id);
employeeService.delete(id);
return "redirect:/employee/list";
}
service&serviceImpl
void delete(Integer id);
@Override
public void delete(Integer id) {
employeeDao.delete(id);
}
dao
void delete(Integer id);
delete from employee where id=#{id}
8. 拦截器,拦截未登录用户
定义拦截器
package com.example.emsthymeleaf.interceptors;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
if (session.getAttribute("user") == null){
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
return true;
}
}
配置拦截器
package com.example.emsthymeleaf.config;
import com.example.emsthymeleaf.interceptors.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
//配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/user/**","/login","regist");
}
//不用再为每一个thymeleaf模板单独开发一个controller请求了
@Override
public void addViewControllers(ViewControllerRegistry registry) {
//viewController:请求路径,viewName:跳转视图
registry.addViewController("login").setViewName("login");
registry.addViewController("regist").setViewName("regist");
registry.addViewController("addEmp").setViewName("addEmp");
}
}
9. 其他一些细节
在html中获取session中的用户名
欢迎 !