IDEA版SpringBoot全教程 08 会员管理系统(中)2

简介: 可以看到,具名的参数有:userName, :createTime,:ipAddr,:lastLoginTime, :nickName, :password,一共6个,可是Map里面只有5个,少了谁呢?

         

在运行,还是报这个错:


java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).


看来还有问题,emmm,错误信息说,我输入了一个参数,但实际上只有0个。


知道了,应该是方法没调对。

54d1e912aa250462eb363c44cb6b2d2e.png

这是部分update方法的重载,竟然没有第二个参数是Map的。

我大意了啊,没有闪!

原来,具名的写法得用另一个对象,叫做namedParameterJdbcTemplate

引入:

@Autowired
NamedParameterJdbcTemplate namedParameterJdbcTemplate;

然后修改saveUser的方法,保存的地方是这样的



54d1e912aa250462eb363c44cb6b2d2e.png

int update = namedParameterJdbcTemplate.update("INSERT INTO `vipmgr`.`user` (`user_name`, `create_time`, `header_pic`, `ip_addr`, `is_delete`, `is_logined`, `is_vip`, `last_login_time`, `nick_name`, `password`, `role_id`, `amt`, `last_sign_date`) " +
  "VALUES (:userName, :createTime, NULL, :ipAddr, '0', '0', '0', NULL, :nickName, :password, '1', 0, NULL)",params);

这下就对了,可是前台又报错了。

b07d2b9ead0a20cca6747c6c9f86b26f.png

fd5d300a5bca9f774946008e3fbcbdc7.png

eval有点问题,为什么呢?

这是因为,我们用ajax请求,已经设置了dataType是json,就不需要eval了。

去掉这一行代码即可。

再保存,就可以了。

8a348ca77ce66ea078bd5f019c39a934.png

咦?中文乱码。。。

解决方案:数据库连接时加上?characterEncoding=utf-8,问题解决。

把alert代码换成这个

$.messager.show({
    title : '提示',
    msg : "保存成功!",
    timeout : 3000,
    showType : 'slide'
});

67f99710f35b959c65a4aca3fdf15697.png

查询与分页

后台简单实现(不分页)

@RequestMapping("queryUsers")
@ResponseBody
public Map<String, Object> queryUsers(HttpServletRequest request){
    //设置返回信息
    Map<String, Object> resultMap = new HashMap();
    resultMap.put("rows",jdbcTemplate.queryForList("select * from user"));
    return resultMap;
}

返回参数需要有一个rows,这边就全部查出来再返回。


data-grid代码


EasyUI的数据表格是(datagrid)以表格格式显示数据,并为选择、排序、分组和编辑数据提供了丰富的支持。


数据网格(datagrid)的设计目的是为了减少开发时间,且不要求开发人员具备指定的知识。它是轻量级的,但是功能丰富。它的特性包括单元格合并,多列页眉,冻结列和页脚,等等。


下面是用户列表的代码:

<div style="padding:5px;background:#fafafa;width:100%;border:1px solid #ccc;height:100%;">
    <table id="dg" title="用户列表" class="easyui-datagrid" fitColumns="true"
           pagination="true" rownumbers="true" url="user/queryUsers" >
        <thead>
        <tr>
            <th field="cb" checkbox="true" align="center"></th>
            <th field="user_name" width="50" align="center">用户名</th>
            <th field="nick_name" width="100" align="center">昵称</th>
            <th field="role_id" width="60" align="center">角色编号</th>
            <th field="create_time" width="200" align="center">创建时间</th>
            <th field="is_vip" width="200" align="center">是否VIP</th>
            <th field="last_login_time" width="200" align="center">上次登录时间</th>
            <th field="is_delete" width="200" align="center">用户状态</th>
        </tr>
        </thead>
    </table>
</div>

启动项目,刷新页面就会访问后台的接口

09ac067ef3755c81078dae392ca79637.png


easyUI本地化

 这时候你会发现,为啥下面的分页模块是英文的?

这是因为我们还没有做本地化,方法如下

找到原来的easyUI下载包,里面有个local,复制到static

aef2c7ee6cc66e5aac0fca6fddf9b5d6.png


引入中文模块:

<script src="locale/easyui-lang-zh_CN.js"></script>

就变成这样啦:

a6c1820aa42c24e9e0265c51a3f8e33c.png



后台分页原理

按照easyUI的套路,如果你要做分页,就得告诉他当前的列表数据,还有总条数。

至于当前查询的是第几页page,还有每页多少条,在发送查询接口的时候,easyui就会帮我们自动带上。

验证:

@RequestMapping("queryUsers")
@ResponseBody
public Map<String, Object> queryUsers(HttpServletRequest request){
    //拼装请求参数
    Map<String, Object> params = handleParamToMap(request);
    System.out.println(params);
    //设置返回信息
    Map<String, Object> resultMap = new HashMap();
    resultMap.put("rows",jdbcTemplate.queryForList("select * from user"));
    return resultMap;
}

{page=1, rows=10}

所以,我们要做的就是根据page和rows,获取总条数和当前查询的数据。

总条数

总条数简单,一句sql解决了。

Integer total = jdbcTemplate.queryForObject("select count(1) from user", Integer.class);

MySQL分页

limit分页公式:curPage是当前第几页;pageSize是一页多少条记录。

代码就写成了这样:

@RequestMapping("queryUsers")
@ResponseBody
public Map<String, Object> queryUsers(HttpServletRequest request){
    //拼装请求参数
    Map<String, Object> params = handleParamToMap(request);
    int page = Integer.parseInt(params.get("page").toString()) ;
    int pageSize = Integer.parseInt(params.get("rows").toString()) ;
    //设置返回信息
    Map<String, Object> resultMap = new HashMap();
    //拿到总条数
    Integer total = jdbcTemplate.queryForObject("select count(1) from user", Integer.class);
    List rows = jdbcTemplate.queryForList("select * from user limit ?,?",(page-1)*pageSize,pageSize);
    resultMap.put("total",total);
    resultMap.put("rows",rows);
    return resultMap;
}

44ad2d82e33c64a630a95f2e1b688335.png

查询按钮控制列表刷新

之前的查询按钮方法为:

$('#search').click(function(){
    $('#ff').form('submit', {
        url:'loadUsers',
        //提交前可以额外添加参数
        onSubmit: function(param){
            //这边只是模拟一下
            param.search = true;
        }
    });
});

当时只是测试一下form的表单提交,实际上不应该这么做。

单独写一个查询方法:

function search(){
    $('#dg').datagrid('load',{
        userName:$('#ff').get(0).userName.value,
        nickName:$('#ff').get(0).nickName.value,
        isVip:$('#ff').get(0).isVip.value,
    });
}

然后查询按钮就调用这个方法即可。

1. $('#search').click(function(){
2. search();
3. });

请求报文如下:

cfe42f687564731bfdfcbaac0513c4ca.png

条件查询(重难点)

欢迎来到本项目最难的点:条件查询,先给出代码:

@RequestMapping("queryUsers")
@ResponseBody
public Map<String, Object> queryUsers(HttpServletRequest request){
    //拼装请求参数
    Map<String, Object> params = handleParamToMap(request);
    int page = Integer.parseInt(params.get("page").toString()) ;
    int pageSize = Integer.parseInt(params.get("rows").toString()) ;
    //拼接where条件
    StringBuffer sb = new StringBuffer(" where 1=1 ");
    List<Object> injectors = new ArrayList<>();
    if(!StrUtil.isEmptyIfStr(params.get("userName"))){
        sb.append("and user_name like ?");
        injectors.add("%"+params.get("userName")+"%");
    }
    if(!StrUtil.isEmptyIfStr(params.get("nickName"))){
        sb.append("and nick_name like ?");
        injectors.add("%"+params.get("nickName")+"%");
    }
    if(!StrUtil.isEmptyIfStr(params.get("isVip"))){
        sb.append("and is_vip = ?");
        injectors.add(params.get("isVip").toString());
    }
    //设置返回信息
    Map<String, Object> resultMap = new HashMap();
    //拿到总条数
    Integer total = jdbcTemplate.queryForObject("select count(1) from user" + sb, injectors.toArray(), Integer.class);
    injectors.add((page-1)*pageSize);
    injectors.add(pageSize);
    List rows = jdbcTemplate.queryForList("select * from user" +  sb +" limit ?,?", injectors.toArray());
    resultMap.put("total",total);
    resultMap.put("rows",rows);
    return resultMap;
}


思路是根据查询的参数是否为空,来拼接对应的where条件。这边用到了一个List,这是为了防止sql注入而采取的必要措施。

这个方法非常重要,请务必好好消化一下。

1977f4790e332d6b971e57a9b881f8a6.png

新增用户后立刻触发刷新

b722a233dd426dd84ee3d4c60b45e334.png

字典翻译

相信你也发现了,就是有些字段显示是数字,这一点其实是不科学的。比如,是否vip,显示一个0,用户怎么知道你这个0是什么意思?解决办法就是用字典翻译。

字典翻译有前台翻译,也有后台翻译,一般我们会单独维护一张字典表,然后做后台翻译的。相关的知识点我们在下一章做讲解。


字典(重要)

这是一款非常经典的教程,我直接挪用了企业里面真实项目的编程技巧。

VipMgrApplication是我们的启动类,加一个容器启动完成的listener

public class VipMgrApplication implements ApplicationListener<ApplicationReadyEvent> {
}

实现onApplicationEvent方法

/**
 * 容器启动完成事件
 * @param applicationReadyEvent
 */
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
  ConfigurableApplicationContext applicationContext = applicationReadyEvent.getApplicationContext();
  JdbcTemplate jdbcTemplate = (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
  //System.out.println(jdbcTemplate);
  //加载所有启动状态的字典数据
  List<Map<String, Object>> dicts = jdbcTemplate.queryForList("select * from t_dict where is_on = 1");
  dictMap = new HashMap<>();
  //为了转换效率,给字典列表加索引
  for (int i = 0; i < dicts.size(); i++) {
    dictMap.put(dicts.get(i).get("dict_code").toString() + dicts.get(i).get("dict_no").toString(),dicts.get(i));
  }
  System.out.println("数据字典加载完毕!" + dictMap);
}

dictMap是我设计的一个静态Map变量

public static Map<String, Map<String, Object>> dictMap = null;

这玩意会在SpringBoot容器启动完毕后就加载。

t_dict表

CREATE TABLE `t_dict` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `dict_code` varchar(20) DEFAULT NULL COMMENT '字典类型',
  `dict_no` varchar(5) DEFAULT NULL,
  `dict_value` varchar(30) DEFAULT NULL,
  `is_on` varchar(1) DEFAULT '1' COMMENT '是否启用',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

模拟数据

INSERT INTO `vipmgr`.`t_dict` (`id`, `dict_code`, `dict_no`, `dict_value`, `is_on`) VALUES ('1', 'isVip', '0', '普通会员', '1');
INSERT INTO `vipmgr`.`t_dict` (`id`, `dict_code`, `dict_no`, `dict_value`, `is_on`) VALUES ('2', 'isVip', '1', 'VIP会员', '1');
INSERT INTO `vipmgr`.`t_dict` (`id`, `dict_code`, `dict_no`, `dict_value`, `is_on`) VALUES ('3', 'isDelete', '0', '未删除', '1');
INSERT INTO `vipmgr`.`t_dict` (`id`, `dict_code`, `dict_no`, `dict_value`, `is_on`) VALUES ('4', 'isDelete', '1', '已删除', '1');
INSERT INTO `vipmgr`.`t_dict` (`id`, `dict_code`, `dict_no`, `dict_value`, `is_on`) VALUES ('5', 'role', '1', '管理员', '1');
INSERT INTO `vipmgr`.`t_dict` (`id`, `dict_code`, `dict_no`, `dict_value`, `is_on`) VALUES ('6', 'role', '2', '注册会员', '1');
INSERT INTO `vipmgr`.`t_dict` (`id`, `dict_code`, `dict_no`, `dict_value`, `is_on`) VALUES ('7', 'role', '3', 'VIP会员', '1');

6a9847c48132dcd84adc2f8b445d89fb.png

启动项目看字典数据


启动项目,看下控制台的打印:


数据字典加载完毕!{isDelete0={id=3, dict_code=isDelete, dict_no=0, dict_value=未删除, is_on=1}, role1={id=5, dict_code=role, dict_no=1, dict_value=管理员, is_on=1}, isVip1={id=2, dict_code=isVip, dict_no=1, dict_value=VIP会员, is_on=1}, role2={id=6, dict_code=role, dict_no=2, dict_value=注册会员, is_on=1}, isVip0={id=1, dict_code=isVip, dict_no=0, dict_value=普通会员, is_on=1}, isDelete1={id=4, dict_code=isDelete, dict_no=1, dict_value=已删除, is_on=1}, role3={id=7, dict_code=role, dict_no=3, dict_value=VIP会员, is_on=1}}


这样做的好处就是,在容器启动后就加载所有的数据字典,放到Map里面。到时候别的地方如果有字典转换的需求,就非常快速。


用户数据查出来后,用lamda表达式进行数据翻译:

//数据字典转换
rows.forEach((map) -> {
    //是否VIP翻译
    map.put("is_vip",VipMgrApplication.dictMap.get("isVip" + map.get("is_vip")).get("dict_value"));
    //角色名称翻译
    map.put("roleName",VipMgrApplication.dictMap.get("role" + map.get("role_id")).get("dict_value"));
    //用户状态翻译
    map.put("is_delete",VipMgrApplication.dictMap.get("isDelete" + map.get("is_delete")).get("dict_value"));
});

103b5102e522aa8dda5342bc02ad16ba.png


角色编号

角色ID可能还会用到,所以保留,我们增加了roleName返回,于是乎:

<div style="padding:5px;background:#fafafa;width:100%;border:1px solid #ccc;height:100%;">
    <table id="dg" title="用户列表" class="easyui-datagrid" fitColumns="true"
           pagination="true" rownumbers="true" url="user/queryUsers" >
        <thead>
        <tr>
            <th field="cb" checkbox="true" align="center"></th>
            <th field="user_name" width="150" align="center">用户名</th>
            <th field="nick_name" width="100" align="center">昵称</th>
            <th field="role_id" width="60" align="center" hidden>角色编号</th>
            <th field="roleName" width="60" align="center">角色</th>
            <th field="create_time" width="200" align="center">创建时间</th>
            <th field="is_vip" width="200" align="center">是否VIP</th>
            <th field="last_login_time" width="200" align="center">上次登录时间</th>
            <th field="is_delete" width="200" align="center">用户状态</th>
        </tr>
        </thead>
    </table>
</div>

用户名扩展到150,然后隐藏角色编号。

d15d4255e2f30773dd011b06cd5fa3a6.png

easyUI给我们提供了很多套皮肤,挑一个自己喜欢的吧,毕竟默认的皮肤太丑了。

皮肤库文件在这

9d21527ed6694c84262aa84fc5a8fda4.png

换一个css就行

<link rel="stylesheet" type="text/css" href="themes/material/easyui.css">

9125f8cc307e002ea8ae24c1f9688c88.png


我换成了这种风格,你也可以换成自己喜欢的。

我们希望不同的字典值有一个默认的颜色,这样显得层次感强一点。

添加color字段

1c1d78188d31a0aaa6421f4496c772fe.png

2a578ebb53c4498d8c034b4a429dc6fe.png


/**
 * 容器启动完成事件
 * @param applicationReadyEvent
 */
@Override
public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
  ConfigurableApplicationContext applicationContext = applicationReadyEvent.getApplicationContext();
  JdbcTemplate jdbcTemplate = (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
  //System.out.println(jdbcTemplate);
  //加载所有启动状态的字典数据
  List<Map<String, Object>> dicts = jdbcTemplate.queryForList("select * from t_dict where is_on = 1");
  dictMap = new HashMap<>();
  //为了转换效率,给字典列表加索引
  for (int i = 0; i < dicts.size(); i++) {
    //如果有颜色,则自动添加font标签
    if(!StrUtil.isEmptyIfStr(dicts.get(i).get("color"))){
      dicts.get(i).put("dict_value",String.format("<font color='%s'>%s</font>",dicts.get(i).get("color"),dicts.get(i).get("dict_value")));
    }
    dictMap.put(dicts.get(i).get("dict_code").toString() + dicts.get(i).get("dict_no").toString(),dicts.get(i));
  }
  System.out.println("数据字典加载完毕!" + dictMap);
}

如果color不为空,就重新渲染dict_value

我故意修改了一些数据,得到这样的效果

38fcadc45d062ad70f62100ba45cd44f.png



相关文章
|
11天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的服装商城管理系统
基于Java+Springboot+Vue开发的服装商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的服装商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
33 2
基于Java+Springboot+Vue开发的服装商城管理系统
|
8天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
23 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的蛋糕商城管理系统
基于Java+Springboot+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的蛋糕商城管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的美容预约管理系统
基于Java+Springboot+Vue开发的美容预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的美容预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的美容预约管理系统
|
9天前
|
JavaScript Java 关系型数据库
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
本文介绍了一个基于Spring Boot和Vue.js实现的在线考试系统。随着在线教育的发展,在线考试系统的重要性日益凸显。该系统不仅能提高教学效率,减轻教师负担,还为学生提供了灵活便捷的考试方式。技术栈包括Spring Boot、Vue.js、Element-UI等,支持多种角色登录,具备考试管理、题库管理、成绩查询等功能。系统采用前后端分离架构,具备高性能和扩展性,未来可进一步优化并引入AI技术提升智能化水平。
毕设项目&课程设计&毕设项目:基于springboot+vue实现的在线考试系统(含教程&源码&数据库数据)
|
11天前
|
Java 关系型数据库 MySQL
毕设项目&课程设计&毕设项目:springboot+jsp实现的房屋租租赁系统(含教程&源码&数据库数据)
本文介绍了一款基于Spring Boot和JSP技术的房屋租赁系统,旨在通过自动化和信息化手段提升房屋管理效率,优化租户体验。系统采用JDK 1.8、Maven 3.6、MySQL 8.0、JSP、Layui和Spring Boot 2.0等技术栈,实现了高效的房源管理和便捷的租户服务。通过该系统,房东可以轻松管理房源,租户可以快速找到合适的住所,双方都能享受数字化带来的便利。未来,系统将持续优化升级,提供更多完善的服务。
毕设项目&课程设计&毕设项目:springboot+jsp实现的房屋租租赁系统(含教程&源码&数据库数据)
|
11天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的房产销售管理系统
基于Java+Springboot+Vue开发的房产销售管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的房产销售管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
25 3
基于Java+Springboot+Vue开发的房产销售管理系统
|
12天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的反诈视频宣传系统
基于Java+Springboot+Vue开发的反诈视频宣传系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的反诈视频宣传管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
41 4
基于Java+Springboot+Vue开发的反诈视频宣传系统
|
13天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的健身房管理系统
基于Java+Springboot+Vue开发的健身房管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的健身房管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
42 5
基于Java+Springboot+Vue开发的健身房管理系统
|
12天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
基于Java+Springboot+Vue开发的医院门诊预约挂号系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的门诊预约挂号管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
33 2
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
下一篇
无影云桌面