IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring Boot项目学习之通用权限管理项目02 -> 正文阅读

[Java知识库]Spring Boot项目学习之通用权限管理项目02

接着上一篇,这里完成最基本的页面分页展示的功能。这也是权限管理系统的最基本功能的组成。

1. 创建业务层

创建service包,在该包下创建UrmsUserService.java 接口类及其实现类。
UrmsUserService.java

public interface UserService {

    /**
     * 新增用户(完整信息)
     * @param urmsUser
     * @return
     */
    int insert(UrmsUser urmsUser);


    /**
     * 新增用户(不完整信息)
     * @param urmsUser
     * @return
     */
    int insertSelective(UrmsUser urmsUser);
    

    /**
     * 根据ID修改用户信息(完全修改)
     * @param urmsUser
     * @return
     */
    int updateByPrimaryKey(UrmsUser urmsUser);


    /**
     * 根据ID修改用户信息(部分修改)
     * @param urmsUser
     * @return
     */
    int updateByPrimaryKeySelective(UrmsUser urmsUser);

    /**
     * 根据ID删除用户信息
     * @param urmsUserId
     * @return
     */
    int deleteByPrimaryKey(Integer urmsUserId);


    /**
     * 根据ID查询用户
     * @param urmsUserId
     * @return
     */
    UrmsUser get(Integer urmsUserId);
}

UrmsUserServiceImpl.java

@Service("urmsUserService")
public class UrmsUserServiceImpl implements UrmsUserService {
    
   @Autowired
   private UrmsUserMapper urmsUserMapper;

    
   public int insert(UrmsUser urmsUser){
        return urmsUserMapper.insert(urmsUser);
    }


   public int insertSelective(UrmsUser urmsUser){
       return urmsUserMapper.insertSelective(urmsUser);
   }


   public int updateByPrimaryKey(UrmsUser urmsUser){
       return urmsUserMapper.updateByPrimaryKey(urmsUser);
   }


   public int updateByPrimaryKeySelective(UrmsUser urmsUser){
       return urmsUserMapper.updateByPrimaryKeySelective(urmsUser);
   }

   
   public int deleteByPrimaryKey(Integer urmsUserId){
       return urmsUserMapper.deleteByPrimaryKey(urmsUserId);
   }


   public UrmsUser get(Integer urmsUserId){
       return urmsUserMapper.selectByPrimaryKey(urmsUserId);
   }
}

2.创建控制层

在controller包下创建UrmsUserController.java类。
UrmsUserController.java

@Controller
@RequestMapping("/user")
public class UrmsUserController {

    @Autowired
    private UrmsUserService urmsUserService;

    
    /**
     * 通过ID查询哦那个户信息
     * @param urmsUserId
     * @return
     */
    @GetMapping("/search")
    @ResponseBody
    public R search(Integer urmsUserId){
        Map<String, Object> res = new HashMap<>();
        UrmsUser urmsUser = urmsUserService.get(urmsUserId);
        res.put("user", urmsUser);
        return R.ok(res);
    }
}

3.进行测试

接下来进行简要的测试,这里使用Junit单元测试,所以添加测试框架依赖。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

然后在测试启动类UrmsApplicationTests.java中添加测试方法。这里有一点需要注意。需要在该类上添加必要的注解。

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UrmsApplicationTests {
}

SpringRunner.class:让 junit 与 Spring 环境进行整合

SpringBootTest(classes={webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT}) 的作用

  • 1.当前类为 Spring Boot 的测试类
  • 2.加载 Spring Boot 启动类。
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UrmsApplicationTests {

    @Autowired
    private UrmsUserService urmsUserService;

    @Test
    public void get(){
        Integer urmsUserId = 1;
        UrmsUser urmsUser = urmsUserService.get(urmsUserId);
        Assert.assertEquals(urmsUserId, urmsUser.getUserId());
        Assert.assertEquals("admin", urmsUser.getUsername());
    }

}

启动测试上述断言,出现如下界面则就测试通过。
在这里插入图片描述
测试带有事务的方法,并且测试成功后,避免对数据库的数据有影响。此时我们需要测试方法运行完毕后回滚事务。

    @Test
    @Transactional
    @Rollback(true)
    public void insert(){
        UrmsUser user = new UrmsUser();
        user.setUsername("test");
        user.setRealname("测试用户");
        user.setPassword("abc123");
        user.setPhone("123456789");
        user.setEmail("test001@email.cn");
        user.setSex((byte) 0);
        Integer userId = urmsUserService.insert(user);
        Assert.assertNotNull(userId);
        System.out.println("返回ID为:" + user.getUserId());
    }

在测试的时候,如果不想测试某个方法或者想跳过某个方法可以使用注解@Ignore跳过该方法。

一般自测或者试验一些简单的功能都是使用单元测试,所以需要有一些规范需要遵循,这样对整个项目后续的维护更加友好。

  • 【建议】应该在 /src/test 包下创建测试类,不应该在其他包中创建,而且创建的包应该和 /src/java 包保持一致。
  • 【建议】最好不要在 main 方法内编写测试内容。
  • 【强制】测试类和测试方法的访问权限必须是 public。不然运行时会报错。
  • 【建议】测试类类名命名规范:测试类类名=被测试类类名+“Test”。
  • 【建议】测试方法名命名规范:测试方法名=被测试方法名 或 测试方法名=被测试方法名+ “Test”
  • 【建议】测试方法中不建议用人肉测试方法,即打印日志的方式来人眼观察是否结果正确,正确方式应该使用 Assert 等测试类专用方法。

4.用户管理之分页管理

一个页面需要引入很多静态资源,对于一些公共的静态资源,如果每个页面都引入的话,那么会使得页面布局十分臃肿;最好的做法是将这些公共的资源单独放在一个文件中,然后在需要的地方引入这个文件即可。
创建include.html

    <head th:fragment="header">
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title></title>
        <meta name="keywords" content="">
        <meta name="description" content="">

        <link href="../static/css/bootstrap.min.css?v=3.3.7"
              th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
        <link href="../static/css/font-awesome.css?v=4.4.0"
              th:href="@{/css/font-awesome.css}" rel="stylesheet">
        <link href="../static/css/plugins/bootstrap-table/bootstrap-table.min.css"
              th:href="@{/css/plugins/bootstrap-table/bootstrap-table.min.css}"
              rel="stylesheet">
        <link href="../static/css/plugins/zTree/zTreeStyle/zTreeStyle.css"
              th:href="@{/css/plugins/zTree/zTreeStyle/zTreeStyle.css}"
              rel="stylesheet">
        <link href="../static/css/plugins/jqTreeGrid/jquery.treegrid.css"
              th:href="@{/css/plugins/jqTreeGrid/jquery.treegrid.css}"
              rel="stylesheet">
        <!--summernote css -->
        <link href="../static/css/plugins/summernote/summernote-0.8.8.css"
              th:href="@{/css/plugins/summernote/summernote-0.8.8.css}"
              rel="stylesheet">
        <link href="../static/css/animate.css"
              th:href="@{/css/animate.css}"
              rel="stylesheet">
        <link href="../static/css/plugins/chosen/chosen.css"
              th:href="@{/css/plugins/chosen/chosen.css}"
              rel="stylesheet">
        <link href="../static/css/style.css?v=4.1.0"
              th:href="@{/css/style.css}"
              rel="stylesheet">
    </head>
    <div th:fragment="footer">
        <script src="../static/js/jquery.min.js?v=2.1.4"
                th:src="@{/js/jquery.min.js}"></script>
        <script src="../static/js/bootstrap.min.js?v=3.3.7"
                th:src="@{/js/bootstrap.min.js}"></script>
        <script src="../static/js/plugins/bootstrap-table/bootstrap-table.min.js"
                th:src="@{/js/plugins/bootstrap-table/bootstrap-table.min.js}"></script>
        <script src="../static/js/plugins/bootstrap-table/bootstrap-table-mobile.min.js"
                th:src="@{/js/plugins/bootstrap-table/bootstrap-table-mobile.min.js}"></script>
        <script src="../static/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"
                th:src="@{/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js}"></script>
        <script src="../static/js/plugins/validate/jquery.validate.min.js"
                th:src="@{/js/plugins/validate/jquery.validate.min.js}"></script>
        <script src="../static/js/plugins/validate/messages_zh.min.js"
                th:src="@{/js/plugins/validate/messages_zh.min.js}"></script>
        <script src="../static/js/plugins/zTree/jquery.ztree.all.min.js"
                th:src="@{/js/plugins/zTree/jquery.ztree.all.min.js}"></script>
        <script src="../static/js/plugins/jqTreeGrid/jquery.treegrid.min.js"
                th:src="@{/js/plugins/jqTreeGrid/jquery.treegrid.min.js}"></script>
        <script src="../static/js/plugins/jqTreeGrid/jquery.treegrid.extension.js"
                th:src="@{/js/plugins/jqTreeGrid/jquery.treegrid.extension.js}"></script>
        <script src="../static/js/plugins/jqTreeGrid/jquery.treegrid.bootstrap3.js"
                th:src="@{/js/plugins/jqTreeGrid/jquery.treegrid.bootstrap3.js}"></script>
        <script src="../static/js/plugins/chosen/chosen.jquery.js"
                th:src="@{/js/plugins/chosen/chosen.jquery.js}"></script>
        <script src="../static/js/plugins/layer/layer.js"
                th:src="@{/js/plugins/layer/layer.js}"></script>
        <script src="../static/js/content.js?v=1.0.0"
                th:src="@{/js/content.js}"></script>
        <!--summernote-->
        <script src="../static/js/plugins/summernote/summernote.js"
                th:src="@{/js/plugins/summernote/summernote.js}"></script>
        <script src="../static/js/plugins/summernote/summernote-zh-CN.min.js"
                th:src="@{/js/plugins/summernote/summernote-zh-CN.min.js}"></script>
        <script src="../static/js/ajax-util.js"
                th:src="@{/js/ajax-util.js}"></script>
        <script th:inline="javascript">
            var ctx = [[${#request.getContextPath()}]];
        </script>
    </div>

4.1 添加用户管理页面

创建user文件夹,在其文件夹下创建main.html页面。
main.html

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<meta charset="utf-8">
<head th:include="include :: header"></head>
<style>
    body{height:auto;font-family: "Microsoft YaHei";}
    button{font-family: "SimSun","Helvetica Neue",Helvetica,Arial;}
</style>
<body class="gray-bg">
<div class="wrapper wrapper-content">
    <div class="row">
        <div class="col-sm-12">
            <div class="ibox">
                <div class="ibox-content">
                    <form id="userForm" class="form-horizontal m-t">
                        <input id="organizationId" name="organizationId" class="form-control" type="hidden">
                        <div class="form-group">
                            <label class="col-sm-1 control-label">帐号:</label>
                            <div class="col-sm-2">
                                <input id="username" name="username" class="form-control" type="text">
                            </div>
                            <label class="col-sm-1 control-label">电话:</label>
                            <div class="col-sm-2">
                                <input id="phone" name="phone" class="form-control" type="text">
                            </div>
                        </div>
                    </form>
                </div>
            </div>
            <div class="ibox">
                <div class="ibox-content">
                    <div class="fixed-table-toolbar">
                        <div class="columns pull-left">
                            <button id="serachBtn" class="btn btn-success" onclick="javascript:reLoad()">
                                <i class="fa fa-search" aria-hidden="true"></i>查询
                            </button>
                            <button shiro:hasPermission="system:upmsUser:add" type="button" class="btn  btn-primary" onclick="add()">
                                <i class="fa fa-plus" aria-hidden="true"></i>添加
                            </button>
                            <button shiro:hasPermission="system:upmsUser:batchRemove" type="button" class="btn  btn-danger"
                                    onclick="batchRemove()">
                                <i class="fa fa-trash" aria-hidden="true"></i>删除
                            </button>
                        </div>
                    </div>
                    <table id="exampleTable" data-mobile-responsive="true">
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>

<div th:include="include :: footer"></div>
<script type="text/javascript" src="/js/appjs/system/urmsUser/main.js"
        th:src="@{/js/appjs/system/urmsUser/main.js}"></script>

<div>
    <script type="text/javascript">
        var s_edit_h = 'hidden';
        var s_remove_h = 'hidden';
        var s_resetPwd_h = 'hidden';
    </script>
</div>
<div shiro:hasPermission="system:upmsUser:edit">
    <script type="text/javascript">
        s_edit_h = '';
    </script>
</div>
<div shiro:hasPermission="system:upmsUser:remove">
    <script type="text/javascript">
        var s_remove_h = '';
    </script>
</div>
<div shiro:hasPermission="system:upmsUser:resetPwd">
    <script type="text/javascript">
        var s_resetPwd_h = '';
    </script>
</div>
</div>

</body>
</html>

接着按照BootStrap 框架提供的网格插件的方式操作表格,为了方便操作,可以将所有的js代码放在统一的文件main.js。
main.js

var prefix = ctx + "/user";

$(function() {
	load();
	getOrganizationTree();
});

function load() {
	$('#exampleTable')
			.bootstrapTable(
					{
						method : 'get', // 服务器数据的请求方式 get or post
						url : prefix + "/list", // 服务器数据的加载地址
						showRefresh : true,
						showToggle : true,
						showColumns : true,
						iconSize : 'outline',
						toolbar : '#exampleToolbar',
						striped : true, // 设置为true会有隔行变色效果
						dataType : "json", // 服务器返回的数据类型
						pagination : true, // 设置为true会在底部显示分页条
						singleSelect : false, // 设置为true将禁止多选
						pageSize : 10, // 如果设置了分页,每页数据条数
						pageNumber : 1, // 如果设置了分布,首页页码
						sidePagination : "server", // 设置在哪里进行分页,可选值为"client" 或者 "server"
                        sortable : true,
                        sortOrder: "asc",
						queryParams : function(params) {
							return {
								//说明:传入后台的参数包括offset开始索引,limit步长,sort排序列,order:desc或者,以及所有列的键值对
                                order : params.order,
                                sort : params.sort,
                                organizationId: $('#organizationId').val(),
					            username:$('#username').val(),
					            phone : $('#phone').val(),
                                limit : params.limit,
                                offset : params.offset
							};
						},

						columns : [
								{
									checkbox : true
								},
																{
									field : 'userId',
									title : '编号'
								},
																{
									field : 'username',
									title : '帐号' ,
                                    sortable: true
								},
																{
									field : 'realname',
									title : '姓名'
								},
								{
                                    field : 'sex',
                                    title : '性别',
                                    formatter : function(value, row, index) {
                                        if(value == 1) {
                                              return "<span class='label label-success'>男</span>";
                                        }else if(value == 0) {
                                            return "<span class='label label-danger'>女</span>";
                                        }
                                        return "<b style='color=red'>未知</b>";
                                    }
                                },
                                {
                                    field : 'upmsOrganizationDO.name',
                                    title : '组织'
                                },
																{
									field : 'phone',
									title : '电话'
								},
																{
									field : 'email',
									title : '邮箱'
								},
																{
									field : 'locked',
									title : '状态',
									formatter : function(value, row, index) {
									    if(value == 1) {
                                            return "<span class='label label-warning'>锁定</span>";
                                        }else if(value == 0) {
                                            return "<span class='label label-success'>正常</span>";
                                        }
                                        return "<span class='label label-danger'>未知</span>";
									}
								},
																{
									field : 'ctime',
									title : '创建时间'
								},
																{
									title : '操作',
									field : 'id',
									align : 'center',
									formatter : function(value, row, index) {
										var e = '<a class="btn btn-primary btn-sm '+s_edit_h+'" href="#" mce_href="#" title="编辑" οnclick="edit(\''
												+ row.userId
												+ '\')"><i class="fa fa-edit"></i></a> ';
										var d = '<a class="btn btn-warning btn-sm '+s_remove_h+'" href="#" title="删除"  mce_href="#" οnclick="remove(\''
												+ row.userId
												+ '\')"><i class="fa fa-remove"></i></a> ';
										var f = '<a class="btn btn-success btn-sm" href="#" title="备用"  mce_href="#" οnclick="resetPwd(\''
												+ row.userId
												+ '\')"><i class="fa fa-key"></i></a> ';
										return e + d ;
									}
								} ]
					});
}
function reLoad() {
	$('#exampleTable').bootstrapTable('refresh');
}

4.2 添加用户首页跳转

    @GetMapping("/main")
    public String urmsUserMain(){
        return "user/main";
    }

4.3 用户分页查询展示

在mapper层中添加分页查询的方法,主要包括查询总记录数和分页列表数。


    // 总记录数
    int count(Map<String,Object> map);
    // 分页列表
    List<UrmsUser> list(Map<String,Object> map);
  <sql id="selectUserVoWhere">
    from urms_user uu
    <where>
      <if test="userId != null and userId != ''"> and uu.user_id = #{userId} </if>
      <if test="username != null and username != ''"> and uu.username like concat('%', #{username}, '%') </if>
      <if test="password != null and password != ''"> and uu.password = #{password} </if>
      <if test="salt != null and salt != ''"> and uu.salt = #{salt} </if>
      <if test="realname != null and realname != ''"> and uu.realname like concat('%', #{realname}, '%') </if>
      <if test="avatar != null and avatar != ''"> and uu.avatar = #{avatar} </if>
      <if test="phone != null and phone != ''"> and uu.phone like concat('%', #{phone}, '%') </if>
      <if test="email != null and email != ''"> and uu.email = #{email} </if>
      <if test="sex != null and sex != ''"> and uu.sex = #{sex} </if>
      <if test="locked != null and locked != ''"> and uu.locked = #{locked} </if>
      <if test="ctime != null and ctime != ''"> and uu.ctime = #{ctime} </if>
    </where>
  </sql>

  <select id="count" resultType="int">
    select count(1)
    <include refid="selectUserVoWhere"/>
  </select>

  <select id="list" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    <include refid="selectUserVoWhere"/>
    <choose>
      <when test="sort != null and sort.trim() != ''">
        order by ${sort} ${order}
      </when>
      <otherwise>
        order by user_id desc
      </otherwise>
    </choose>
    <if test="offset != null and limit != null">
      limit #{offset}, #{limit}
    </if>
  </select>

在service层添加对应的方法。

    /**
     * 总记录数
     * @param map
     * @return
     */
    int count(Map<String,Object> map);


    /**
     * 分页列数
     * @param map
     * @return
     */
    List<UrmsUser> list(Map<String,Object> map);
    @Override
    public int count(Map<String, Object> map) {
        return urmsUserMapper.count(map);
    }

    @Override
    public List<UrmsUser> list(Map<String, Object> map) {
        return urmsUserMapper.list(map);
    }

然后需要封装请求分页数据和响应分页数据,在common包下创建Query.java类,用于存放请求分页数据。

/**
 * 查询参数
 */
public class Query extends LinkedHashMap<String, Object> {
    
    private static final long serialVersionUID = 1L;
    // 行数
    private int offset;
    // 每页条数
    private int limit;

    public Query(Map<String, Object> params) {
        this.putAll(params);
        // 分页参数
        this.offset = Integer.parseInt(params.get("offset").toString());
        this.limit = Integer.parseInt(params.get("limit").toString());
        this.put("offset", offset);
        this.put("page", offset / limit + 1);
        this.put("limit", limit);
    }

    public int getOffset() {
        return offset;
    }

    public void setOffset(int offset) {
        this.put("offset", offset);
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }
}

创建util包,在该包下创建PageUtils.java类,用于封装分页响应数据。

public class  PageUtils implements Serializable {
    private static final long serialVersionUID = 1L;

    private int total;
    private List<?> rows;

    public PageUtils(List<?> list, int total) {
        this.rows = list;
        this.total = total;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public List<?> getRows() {
        return rows;
    }

    public void setRows(List<?> rows) {
        this.rows = rows;
    }

}

最后在控制器中添加分页查询方法。

    /**
     * 分页查询
     * @param params
     * @return
     */
    @ResponseBody
    @GetMapping("/list")
    public PageUtils list(@RequestParam Map<String, Object> params){
        //查询列表数据
        Query query = new Query(params);
        int total = urmsUserService.count(query);
        List<UrmsUser> urmsUserList = urmsUserService.list(query);
        PageUtils pageUtils = new PageUtils(urmsUserList, total);
        return pageUtils;
    }

5.测试效果

启动项目,测试效果。
在这里插入图片描述
源码下载地址:源码下载

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-10-31 11:40:46  更:2022-10-31 11:41:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:21:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码