目录
构建项目
1.创建项目
2.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>3.3.3</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.bdqn</groupId>
<artifactId>JPA-Thymeleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>JPA-Thymeleaf</name>
<description>JPA-Thymeleaf</description>
<properties>
<java.version>21</java.version>
</properties>
<dependencies>
<!-- 引入SpringBoot的Web依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>6.3.3</version>
</dependency>
<!-- 引入JSP引擎依赖,SpringBoot内置Tomcat没有此依赖 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!-- 引入JSTL标签库依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 引入MyBatis-Plus支持(不需要再引入MyBatis包) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.7</version>
</dependency>
<!-- 引入Druid数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.20</version>
</dependency>
<!-- 引入MySQL驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 引入Lombok完成实体类自动Getter/Setter -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 引入Slf4j日志依赖 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- 引入SpringBoot测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
<!-- 配置处理依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 配置热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- thymeleaf依赖布局 -->
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
模型开发
1.实体类
User
@Data
@ToString
@TableName("sys_user")
public class User implements Serializable {
@TableId(type = IdType.AUTO)
@TableField("usr_id")
private Long usrId;
private String usrName;
private String usrPassword;
@TableField("usr_role_id")
private long usrRoleId;
@TableField(exist = false)
private Role role; // 角色信息
private Integer usrFlag;
public User(String usrName, String usrPassword, long usrRoleId, Integer usrFlag) {
this.usrName = usrName;
this.usrPassword = usrPassword;
this.usrRoleId = usrRoleId;
this.usrFlag = usrFlag;
}
}
Role
@Data
@ToString
@TableName("sys_role")
@JsonIgnoreProperties(value = {"hibernateLazyInitializer","handler"})
public class Role implements Serializable {
@TableId(type = IdType.AUTO)
private Long roleId;
private String roleName;
private String roleDesc;
private Long roleFlag;
}
2.Mapper
UserMapper
public interface UserMapper extends BaseMapper<User> {
User login(@Param("usrName") String usrName, @Param("usrPassword")String usrPassword);
Page<User> userPage(@Param("roleId")Long roleId, @Param("usrName") String usrName, Page<User> page);
User getUserByName(String usrName);
int add(User user);
int del(Long usrId);
User getUser(Long usrId);
}
3.MyBatis Mapper SQL
<!-- 映射器 -->
<resultMap id="loginMap" type="com.bdqn.pojo.User">
<id column="usr_id" property="usrId" />
<association property="role" javaType="com.bdqn.pojo.Role">
<id column="role_id" property="roleId" />
<result column="role_name" property="roleName" />
<result column="role_desc" property="roleDesc" />
<result column="role_flag" property="roleFlag" />
</association>
</resultMap>
<!-- 添加 -->
<insert id="add">
insert
sys_user (usr_name,usr_password,usr_role_id,usr_flag)
values (
#{usrName},
#{usrPassword},
#{usrRoleId},
#{usrFlag}
)
</insert>
<!-- 删除 -->
<delete id="del">
delete
from sys_user
where usr_id = #{usrId}
</delete>
<!-- 登录 -->
<select id="login" resultMap="loginMap">
select *
from sys_user u
left join sys_role r on u.usr_role_id = r.role_id
where u.usr_name = #{usrName}
and u.usr_password = #{usrPassword}
</select>
<!-- 根据角色和姓名查询列表及分页 -->
<select id="userPage" resultMap="loginMap">
select a.*,b.* from sys_user a
left join sys_role b on a.usr_role_id=b.role_id
<where>
<if test="usrName!=null">
and a.usr_name like CONCAT('%' , #{usrName} , '%')
</if>
<if test="roleId != null and roleId!=0">
and a.usr_role_id=#{roleId}
</if>
</where>
</select>
<!-- 查询姓名是否重复 -->
<select id="getUserByName" resultType="com.bdqn.pojo.User">
select *
from sys_user
where usr_name = #{usrName}
</select>
<!-- 根据Id查询个人信息 -->
<select id="getUser" resultType="com.bdqn.pojo.User">
select *
from sys_user
where usr_id = #{usrId}
</select>
4.Service层
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
@Resource
private UserMapper userMapper;
@Override
public User login(String usrName, String usrPassword) {
return userMapper.login(usrName, usrPassword);
}
@Override
public User getUser(Long usrId) {
return userMapper.getUser(usrId);
}
@Override
public Page<User> userPage(Long roleId, String usrName, Page<User> page){
return userMapper.userPage(roleId,usrName,page);
}
@Override
public User getUserByName(String usrName) {
return userMapper.getUserByName(usrName);
}
@Override
public int add(User user) {
return userMapper.add(user);
}
@Override
public int del(Long usrId) {
return userMapper.del(usrId);
}
}
功能实现
登录
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
<!-- css -->
<link th:href="@{/css/bootstrap.min.css}" href="../static/css/bootstrap.min.css" rel="stylesheet" />
<link th:href="@{/css/font-awesome.min.css}" href="../static/css/font-awesome.min.css" rel="stylesheet">
<link th:href="@{/css/nprogress.css}" href="../static/css/nprogress.css" rel="stylesheet">
<link th:href="@{/css/green.css}" href="../static/css/green.css" rel="stylesheet">
<link th:href="@{/css/bootstrap-progressbar-3.3.4.min.css}" href="../static/css/bootstrap-progressbar-3.3.4.min.css" rel="stylesheet">
<link th:href="@{/css/jqvmap.min.css}" href="../static/css/jqvmap.min.css" rel="stylesheet" />
<link th:href="@{/css/dropzone.min.css}" href="../static/css/dropzone.min.css" rel="stylesheet">
<link th:href="@{/css/custom.min.css}" href="../static/css/custom.min.css" rel="stylesheet">
</head>
<body class="login">
<div>
<a class="hiddenanchor" id="signup"></a>
<a class="hiddenanchor" id="signin"></a>
<div class="login_wrapper">
<div class="animate form login_form">
<section class="login_content">
<form action="/doLogin" th:action="@{/doLogin}" method="post">
<h1>欢迎登陆</h1>
<div>
<span th:text="${message }" style="color: #ff0000"></span>
</div>
<div>
<input type="text" class="form-control" name="usrName" placeholder="用户名" required="" />
</div>
<div>
<input type="password" class="form-control" name="usrPassword" placeholder="密码" required="" />
</div>
<div>
<button type="submit" class="btn btn-success">登 录</button>
<button type="reset" class="btn btn-default">重 置</button>
</div>
<div class="clearfix"></div>
<div class="separator">
<div class="clearfix"></div>
<br />
<div>
<p>©2019 All Rights Reserved 腾跃科技</p>
</div>
</div>
</form>
</section>
</div>
</div>
</div>
</body>
</html>
@PostMapping("/doLogin")
public String doLogin(String usrName, String usrPassword, Model model, HttpSession session) {
User user = userService.login(usrName, usrPassword);
if (user != null) {
session.setAttribute("loginUser", user);
return "redirect:/main";
} else {
model.addAttribute("msg", "用户名或密码错误,登录失败!");
return "/login";
}
}
列表
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" layout:decorate="~{main}"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
>
<head>
<title>用户管理</title>
<link th:href="@{/localcss/crmlist.css}" href="../../static/localcss/crmlist.css" rel="stylesheet">
</head>
<body>
<div layout:fragment="content">
<div class="">
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12">
<div class="x_panel">
<div class="x_title">
<h2>
用户管理 <i class="fa fa-user"></i>
<small>
- 您可以通过搜索或者其他的筛选项对用户的信息进行编辑、删除等管理操作。^_^
</small>
</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<form method="post" action="/user/list" th:action="@{/user/list}">
<input type="hidden" name="pageIndex" value="1" />
<ul>
<li>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">用户名称</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input name="usrName" type="text" th:value="${usrName}"
class="form-control col-md-6 col-xs-12" value="">
</div>
</div>
</li>
<li>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">角色</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<select name="roleId" id="roleId" class="form-control">
<option value="0">--请选择--</option>
<option th:selected="${role.roleId eq roleId}" th:each="role : ${roles}"
th:value="${role.roleId}" th:text="${role.roleName}" value="">
角色1
</option>
</select>
</div>
</div>
</li>
<li>
<button type="submit" class="btn btn-primary"> 查 询
</button>
</li>
</ul>
</form>
</div>
</div>
</div>
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_content">
<p class="text-muted font-13 m-b-30"></p>
<div id="datatable-responsive_wrapper"
class="dataTables_wrapper form-inline dt-bootstrap no-footer">
<div class="row">
<div class="col-sm-12">
<!-- <a href="/user/add" th:href="@{/user/add}" shiro:hasPermission="用户添加" class="btn btn-success btn-sm">新增用户信息</a> -->
<a href="/user/add" th:href="@{/user/add}" class="btn btn-success btn-sm">新增用户信息</a>
<table id="datatable-responsive"
class="table table-striped table-bordered dt-responsive nowrap dataTable no-footer dtr-inline collapsed"
cellspacing="0" width="100%" role="grid"
aria-describedby="datatable-responsive_info" style="width: 100%;">
<thead>
<tr role="row">
<th class="sorting_asc" tabindex="0"
aria-controls="datatable-responsive" rowspan="1" colspan="1"
aria-label="First name: activate to sort column descending"
aria-sort="ascending">编号
</th>
<th class="sorting" tabindex="0"
aria-controls="datatable-responsive" rowspan="1" colspan="1"
aria-label="Last name: activate to sort column ascending">
用户名
</th>
<th class="sorting" tabindex="0"
aria-controls="datatable-responsive" rowspan="1" colspan="1"
aria-label="Last name: activate to sort column ascending">
角色
</th>
<th class="sorting" tabindex="0"
aria-controls="datatable-responsive" rowspan="1" colspan="1"
aria-label="Last name: activate to sort column ascending">
操作
</th>
</tr>
</thead>
<tbody>
<tr role="row" class="odd" th:each="user : ${userPager.records}">
<td tabindex="0" class="sorting_1" th:text="${user.usrId}">usrId</td>
<td th:text="${user.usrName}">usrName</td>
<td th:text="${user.role.roleName}">roleName</td>
<td>
<div class="btn-group">
<button type="button" class="btn btn-danger">点击操作</button>
<button type="button" class="btn btn-danger dropdown-toggle"
data-toggle="dropdown" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a class="editInfo"
href="/user/edit?usrId=1"
th:href="@{/user/edit(usrId=${user.usrId})}"
data-toggle="tooltip"
data-placement="top" title=""
data-original-title="编辑">编辑</a>
</li>
<li><a class="delInfo" id="del" href="#"
th:onclick="|doDel(this,${user.usrId})|"
data-toggle="tooltip" data-placement="top" title=""
data-original-title="删除">删除</a></li>
</ul>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col-sm-5">
<div class="dataTables_info" id="datatable-responsive_info"
role="status" aria-live="polite">共<span th:text="${userPager.getTotal() }">1</span>条记录
<span th:text="${userPager.current }">1</span>/<span
th:text="${userPager.pages }">1</span>页
</div>
</div>
<div class="col-sm-7">
<div class="dataTables_paginate paging_simple_numbers"
id="datatable-responsive_paginate">
<ul class="pagination">
<li class="paginate_button previous" th:if="${userPager.current gt 0}"><a
href="javascript:page_nav(document.forms[0],1);"
aria-controls="datatable-responsive" data-dt-idx="0"
tabindex="0">首页</a>
</li>
<li class="paginate_button" th:if="${userPager.current gt 1}"><a href="#"
th:onclick="'javascript:page_nav(document.forms[0],'+${userPager.current - 1 }+');'"
aria-controls="datatable-responsive"
data-dt-idx="1"
tabindex="0">上一页</a>
</li>
<li class="paginate_button "
th:if="${(userPager.current) lt userPager.pages}"><a
href="#"
th:onclick="'javascript:page_nav(document.forms[0],'+${userPager.current + 1 }+');'"
aria-controls="datatable-responsive" data-dt-idx="1"
tabindex="0">下一页</a>
</li>
<li class="paginate_button next"
th:if="${(userPager.current) lt userPager.total}"><a
href="#"
th:onclick="'javascript:page_nav(document.forms[0],'+${userPager.pages }+');'"
aria-controls="datatable-responsive" data-dt-idx="7"
tabindex="0">最后一页</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script layout:fragment="js" th:inline="javascript">
// 获取项目路径
/*<![CDATA[*/
var ctxPath = /*[[@{/}]]*/ '';
/*]]>*/
function doDel(obj, usrId) {
if (confirm("你确定需要删除该用户信息吗?")) {
$.ajax({
type: "POST",
url: ctxPath + "user/del/" + usrId,
/*data: {
"usrId": usrId
},*/
dataType: "json",
success: function (data) {
// alert(JSON.stringify(data)); // {"result":"true"}
if (data.result === "true") { // 删除成功:移除删除行
alert("删除成功!");
$(obj).parents("tr").remove();
// window.location.href = project_name() + "/user/list";
}
},
error: function (data) {
alert("对不起,删除失败!");
}
});
}
}
</script>
</html>
@RequestMapping(value = "/list")
public String list(Model model, Long roleId, String usrName, Long pageIndex) {
List<Role> roles = roleService.list();
pageIndex = pageIndex == null ? 1 : pageIndex;
Page<User> userPager = new Page<>();
userPager.setCurrent(pageIndex);
userPager = userService.userPage(roleId, usrName, userPager);
model.addAttribute("roleId", roleId);
model.addAttribute("usrName", usrName);
model.addAttribute("roles", roles);
model.addAttribute("userPager", userPager);
return "user/list";
}
新增
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" layout:decorate="~{main}"
xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout">
<head>
<title>用户添加</title>
<link th:href="@{/localcss/crmlist.css}" href="../static/localcss/crmadd.css" rel="stylesheet">
</head>
<body>
<div layout:fragment="content">
<div class="">
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>新增用户信息 <i class="fa fa-user"></i></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<div class="clearfix"></div>
<form class="form-horizontal form-label-left" th:action="@{/user/save}" action="/user/save" method="post">
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="usrName"> 用户名 <span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input id="usrName" class="form-control col-md-7 col-xs-12"
data-validate-length-range="10" data-validate-words="1" name="usrName" required="required"
placeholder="请输入用户名" type="text">
</div>
</div>
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="usrPassword"> 密码 <span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input id="usrPassword" class="form-control col-md-7 col-xs-12"
data-validate-length-range="10" data-validate-words="1" name="usrPassword" required="required"
placeholder="请输入密码" type="password">
</div>
</div>
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="roleId"> 用户角色 <span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<select name="usrRoleId" id="roleId" class="form-control" required="required">
<option th:each="role:${roles}" th:value="${role.roleId}" th:text="${role.roleName}" value="">角色</option>
</select>
</div>
</div>
<div class="item form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12" for="usrFlag"> 角色状态
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input id="usrFlag" name="usrFlag" type="checkbox" value="1">
(是否启用)
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-3">
<button id="send" type="submit" class="btn btn-success">保存</button>
<button type="button" class="btn btn-primary" id="back">返回</button>
<br /><br />
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script layout:fragment="js" th:inline="javascript">
// 获取项目路径
/*<![CDATA[*/
var ctxPath = /*[[@{/}]]*/ '';
/*]]>*/
$(document).ready(function () {
$("#back").on("click", function () {
window.history.back();
});
$("#usrName").on("blur", function () {
$.ajax({
type: "GET",
url: ctxPath + "user/check",
data: {
"usrName": $("#usrName").val(),
},
dataType: "json",
success: function (data) {
// alert(JSON.stringify(data)); // {"result":"true"}
if (data.result === "true") { // 检查有重复:返回"true"
alert("用户名重复了!");
// $("#usrName").focus();
}
},
error: function (data) {
alert("对不起,检查失败!");
}
});
});
});
</script>
</html>
@RequestMapping("/add")
public String add(Model model) {
List<Role> roles = roleService.list();
model.addAttribute("roles", roles);
return "user/add";
}
@RequestMapping("/save")
public String save(User user) {
if (user.getUsrFlag()==null){
user.setUsrFlag(0);
}
int add = userService.add(user);
if (add>0){
return "redirect:/user/list";
}else{
return "user/add";
}
}
删除
function doDel(obj, usrId) {
if (confirm("你确定需要删除该用户信息吗?")) {
$.ajax({
type: "POST",
url: ctxPath + "user/del/" + usrId,
/*data: {
"usrId": usrId
},*/
dataType: "json",
success: function (data) {
// alert(JSON.stringify(data)); // {"result":"true"}
if (data.result === "true") { // 删除成功:移除删除行
alert("删除成功!");
$(obj).parents("tr").remove();
// window.location.href = project_name() + "/user/list";
}
},
error: function (data) {
alert("对不起,删除失败!");
}
});
}
}
@ResponseBody
@RequestMapping("/del/{usrId}")
public Map del(@PathVariable Long usrId) {
Map map = new HashMap();
int add = userService.del(usrId);
if (add>0){
map.put("result", "true");
}else{
map.put("result", "false");
}
return map;
}