1.创立SpringBoot我的项目,引入依赖

pom.xml

<?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.5.4</version>        <relativePath/> <!-- lookup parent from repository -->    </parent>    <groupId>com.example</groupId>    <artifactId>ems-thymeleaf</artifactId>    <version>0.0.1-SNAPSHOT</version>    <name>ems-thymeleaf</name>    <description>ems-thymeleaf</description>    <properties>        <java.version>1.8</java.version>    </properties>    <dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-thymeleaf</artifactId>            <version>2.5.1</version>        </dependency>        <dependency>            <groupId>mysql</groupId>            <artifactId>mysql-connector-java</artifactId>            <version>8.0.26</version>        </dependency>        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>druid</artifactId>            <version>1.2.6</version>        </dependency>        <dependency>            <groupId>org.mybatis.spring.boot</groupId>            <artifactId>mybatis-spring-boot-starter</artifactId>            <version>2.2.0</version>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>    </dependencies>    <build>        <plugins>            <plugin>                <groupId>org.springframework.boot</groupId>                <artifactId>spring-boot-maven-plugin</artifactId>            </plugin>        </plugins>    </build></project>

2.批改配置文件application.yml

server:  port: 8989  servlet:    context-path: /emsspring:  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: debugmybatis:  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;@Configurationpublic 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文件中设置拜访随机验证码
<td valign="middle" align="right">   验证码:   <img id="num" th:src="@{/user/generateImageCode}" />   <a href="javascript:;" onclick="changeImageCode()">换一张</a>   <script>      function changeImageCode(){         document.getElementById("num").src='[[@{/user/generateImageCode}]]?' + (new Date()).getTime()      }   </script></td>

5.用户注册

  1. 引入lombok
<dependency>    <groupId>org.projectlombok</groupId>    <artifactId>lombok</artifactId>    <version>1.18.20</version></dependency>
  1. 创立实体类User
package com.example.emsthymeleaf.entity;import lombok.Data;@Datapublic 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@Transactionalpublic 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
<?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.example.emsthymeleaf.dao.UserDao">    <insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id">        insert into user values(#{id},#{username},#{realname},#{password},#{gender})    </insert>    <select id="getUserByUserName" parameterType="String" resultType="User">        select id,username,realname,password,gender from user where username=#{username}    </select></mapper>
  1. 注册页面.html
<div id="content">    <p id="whereami">    </p>    <h1>        注册<span style="color: darkred;" th:text="${#request.getParameter('err')}"></span>    </h1>    <form th:action="@{/user/regist}" 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="0" checked="checked"/>                    女                    <input type="radio" class="inputgri" name="gender" value="1"/>                </td>            </tr>            <tr>                <td valign="middle" align="right">                    验证码:                    <img id="num" th:src="@{/user/generateImageCode}" />                    <a href="javascript:;" onclick="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="立刻注册 &raquo;" />            <a th:href="@{/user/generateImageCode}">已有账号,返回登录</a>        </p>    </form></div>

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

@Overridepublic 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

<div id="content">   <p id="whereami">   </p>   <h1>      欢送进入,请登录!   </h1>   <p style="color:red;" th:if="${#request.getParameter('err')}" th:text=" '谬误:' + ${#request.getParameter('err')}"></p>   <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="点我登录 &raquo;" />         &nbsp;&nbsp;         <a th:href="@{/regist}">还没有账号,立刻注册</a>      </p>   </form></div>

6.2 用户退出

controller

//用户退出@RequestMapping("/logout")public String logout( HttpSession session){    session.invalidate();    return "redirect:/login";}

html

<a th:href="@{/user/logout}">平安退出</a>

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;@Configurationpublic 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

@Overridepublic void save(Employee employee) {    employeeDao.save(employee);}

dao

void save(Employee employee);

dao.xml

<insert id="save" parameterType="Employee" useGeneratedKeys="true" keyProperty="id">    insert into employee values (#{id},#{name},#{photo},#{salary},#{birthday})</insert>

html

<form th:action="@{/employee/save}" 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>

7.2 员工列表

controller

@RequestMapping("list")public String list(Model model) {    model.addAttribute("list", employeeService.list());    return "emplist";}

serviceImpl

@Overridepublic List<Employee> list() {    return employeeDao.list();}

dao

List<Employee> list();

dao.xml

<select id="list" resultType="Employee">    select id, name, photo, salary, birthday from `employee`</select>

html

<div id="content">   <p id="whereami">   </p>   <h1>      欢送 小陈!   </h1>   <table class="table">      <tr class="table_header">         <td>            编号         </td>         <td>            姓名         </td>         <td>            头像         </td>         <td>            工资         </td>         <td>            生日         </td>         <td>            操作         </td>      </tr>      <tr class="row1" th:each="emp:${list}">         <td>            <span th:text="${emp.id}"></span>         </td>         <td>            <span th:text="${emp.name}"></span>         </td>         <td>            <img th:src="@{/}+${emp.photo}" width="60">         </td>         <td>            <span th:text="${emp.salary}"></span>          </td>          <td>              <span th:text="${#dates.format(emp.birthday,'yyyy/MM/dd')}"></span>          </td>          <td>              <a href="javascript:;" th:onclick="'deleteEmployee(' + ${emp.id} + ')'">删除</a>              <a th:href="@{/employee/details(id=${emp.id})}">更新</a>          </td>       </tr>       <script>           function deleteEmployee(id){               if(window.confirm("是否删除这条记录?")){                   location.href='[[@{/employee/delete?id=}]]' + id               }           }       </script>   </table>   <p>      <input type="button" class="button" value="增加" onclick="addEmp()"/>      <script type="text/javascript">         function addEmp() {            window.location ='[[@{/addEmp}]]'         }      </script>   </p></div>

thymeleaf须要留神的点

  1. 在<img>标签中获取以后门路的动态文件:<img th:src="@{/}+${emp.photo}" width="60">,将门路和文件名连接起来
  2. 须要批改application.yml文件,裸露哪些资源能够通过我的项目名拜访

    resources:      static-locations: classpath:/static/,file:${img.file.dir}
  3. <a>标签链接到带参数的地址:<a href="localhost:8989/ems/employee/details?id=[从th参数中获取的id值]">更新</a>,在th中应该写为:<a th:href="@{/employee/details(id=${emp.id})}">更新</a>
  4. 将标签中的链接改为响应click事件的html语句:
<a href="javascript:;" th:onclick="'deleteEmployee(' + ${emp.id} + ')'">删除</a><script>    function deleteEmployee(id){        if(window.confirm("是否删除这条记录?")){            location.href='[[@{/employee/delete?id=}]]' + id        }    }</script>

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);
@Overridepublic Employee findById(Integer id) {    return employeeDao.findById(id);}

dao

Employee findById(Integer id);
<select id="findById" parameterType="Integer" resultType="Employee">    select id, name, photo, salary, birthday from employee where id = #{id}</select>

html显示编辑员工信息页面

<form th:action="@{/employee/update}" 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">            <span th:text="${employee.id}"></span>            <input type="hidden" th:value="${employee.id}" name="id">         </td>      </tr>      <tr>         <td valign="middle" align="right">            姓名:         </td>         <td valign="middle" align="left">            <input type="text" class="inputgri" name="name" th:value="${employee.name}"/>         </td>      </tr>      <tr>         <td valign="middle" align="right">            以后头像:         </td>         <td valign="middle" align="left">            <img th:src="@{/} + ${employee.photo}" width="60">            <input type="hidden" name="photo" th:value="${employee.photo}">         </td>      </tr>      <tr>         <td valign="middle" align="right">            抉择新头像:         </td>         <td valign="middle" align="left">            <input type="file" name="img" />         </td>      </tr>      <tr>         <td valign="middle" align="right">            工资:         </td>         <td valign="middle" align="left">            <input type="text" class="inputgri" name="salary" th:value="${employee.salary}"/>         </td>      </tr>      <tr>         <td valign="middle" align="right">            生日:         </td>         <td valign="middle" align="left">            <input type="text" class="inputgri" name="birthday" th:value="${#dates.format(employee.birthday,'yyyy/MM/dd')}"/>         </td>      </tr>   </table>   <p>      <input type="submit" class="button" value="更新" />      <input type="button" class="button" value="返回列表" />   </p></form>

留神两个暗藏类型的input,因为<span>和<img>标签的信息无奈通过申请传递,所以这两个标签上面须要设置暗藏类型的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);
@Overridepublic void update(Employee employee) {    employeeDao.update(employee);}

dao

void update(Employee employee);
<update id="update" parameterType="Employee">    update employee set name=#{name},photo=#{photo},salary=#{salary},birthday=#{birthday} where id = #{id}</update>

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);
@Overridepublic void delete(Integer id) {    employeeDao.delete(id);}

dao

void delete(Integer id);
<delete id="delete" parameterType="Integer">    delete from employee where id=#{id}</delete>

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;@Configurationpublic 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中的用户名

    欢送 <span th:text="${#session.getAttribute('user').realname}"></span>!