SpringBoot使用Thymeleaf模板实现一个小项目

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.设置随机图形验证码

  1. 引入验证码生成工具VerifyCodeUtils
  2. 在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);

    }
}
  1. 在thymeleaf的html文件中设置访问随机验证码

   验证码:
   
   换一张
   

5.用户注册

  1. 引入lombok

    org.projectlombok
    lombok
    1.18.20
  1. 创建实体类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;
}
  1. 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";
}
  1. 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);
}
  1. 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);

    }
}
  1. dao
package com.example.emsthymeleaf.dao;

import com.example.emsthymeleaf.entity.User;

public interface UserDao {
    void save(User user);
    User getUserByUserName(String username);
}
  1. xml



    
        insert into user values(#{id},#{username},#{realname},#{password},#{gender})
    
    
  1. 注册页面.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 添加员工

  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");
    }
}
  1. 添加员工的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需要注意的点

  1. 标签中获取当前路径的静态文件:,将路径和文件名连接起来
  2. 需要修改application.yml文件,暴露哪些资源可以通过项目名访问

    resources:
          static-locations: classpath:/static/,file:${img.file.dir}
  3. 标签链接到带参数的地址:更新,在th中应该写为:更新
  4. 标签中的链接改为响应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中的用户名

    欢迎 !

你可能感兴趣的:(springboot)