上一章我们将RMS后台管理系统搭建完毕,本章我们就在这个系统上实现录入游戏配置的功能。目前我们需要配置四项,每个等级的人物属性,每个等级的升级经验,游戏地图,地图中的怪物。下面我们以游戏地图配置为例子,实现对它的增删查改功能。
一、数据访问层的实现
首先,我们需要定义地图类,这个类在各个模块通用,因此要定义在facade模块中。我们新建一个包com.idlewow.map.model,在其中新建WowMap类,代码如下:
package com.idlewow.map.model;
import com.idlewow.common.model.BaseModel;
import lombok.Data;
import java.io.Serializable;
@Data
public class WowMap extends BaseModel implements Serializable {
private String name;
private Integer occupy;
private String description;
}
然后,我们在core模块中实现数据访问层的逻辑。新建com.idlewow.map.mapper包,并新建一个接口类WowMapMapper,在接口中定义我们需要用到的一些增删查改方法,代码如下:
package com.idlewow.map.mapper;
import com.idlewow.map.model.WowMap;
import com.idlewow.query.model.WowMapQueryParam;
import java.util.List;
public interface WowMapMapper {
int insert(WowMap wowMap);
int batchInsert(List<WowMap> list);
int update(WowMap levelProp);
int delete(String id);
WowMap find(String id);
List<WowMap> list(WowMapQueryParam queryParam);
int count(WowMapQueryParam queryParam);
}
Mapper接口类,只定义了方法,具体实现需要我们在该包下新建一个WowMapMapper.xml文件,在这个文件中,通过SQL语句实现接口中的方法:
<?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.idlewow.map.mapper.WowMapMapper">
<resultMap id="BaseResultMap" type="com.idlewow.map.model.WowMap">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="occupy" property="occupy"/>
<result column="description" property="description"/>
<result column="create_user" property="createUser"/>
<result column="update_user" property="updateUser"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
<result column="is_delete" property="isDelete"/>
<result column="version" property="version"/>
</resultMap>
<!-- 添加 -->
<insert id="insert">
insert into map (name, occupy, description, create_user)
values (#{name}, #{occupy}, #{description}, #{createUser})
</insert>
<!-- 批量添加 -->
<insert id="batchInsert">
insert into map (name, occupy, description, create_user)
values
<foreach collection="list" item="item" separator=",">
(#{item.name}, #{item.occupy}, #{item.description}, #{item.createUser})
</foreach>
</insert>
<!-- 修改 -->
<update id="update">
update map
set name = #{name},
occupy = #{occupy},
description = #{description},
update_user = #{updateUser},
version = version + 1
where id = #{id} and is_delete = 0
</update>
<!-- 删除 -->
<update id="delete" parameterType="String">
update map
set is_delete = 1
where id = #{id}
</update>
<!-- id查询 -->
<select id="find" resultMap="BaseResultMap">
select *
from map
where id = #{id} and is_delete = 0
</select>
<!-- 列表查询总数 -->
<select id="count" resultType="int">
select count(1)
from map
<where>
is_delete = 0
<if test="name != null and name != ''">
and name like concat('%', #{name}, '%')
</if>
</where>
</select>
<!-- 列表查询 -->
<select id="list" resultMap="BaseResultMap">
select *
from map
<where>
is_delete = 0
<if test="name != null and name != ''">
and name like concat('%', #{name}, '%')
</if>
</where>
<if test="pageParam != null">
limit ${(pageParam.pageIndex - 1) * pageParam.pageSize}, ${pageParam.pageSize}
</if>
</select>
</mapper>
WowMapMapper.xml
最后,我们新建com.idlewow.map.manager包,新建一个类WowMapManager,此类通过调用mapper来实现具体业务:
package com.idlewow.map.manager;
import com.idlewow.common.model.PageList;
import com.idlewow.map.mapper.WowMapMapper;
import com.idlewow.map.model.WowMap;
import com.idlewow.query.model.WowMapQueryParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class WowMapManager {
@Autowired
WowMapMapper wowMapMapper;
public void insert(WowMap wowMap) {
int effected = wowMapMapper.insert(wowMap);
if (effected == 0) {
throw new RuntimeException("sql effected 0 rows");
}
}
public void batchInsert(List<WowMap> list) {
int splitSize = 100;
int index = 0;
int total = list.size();
while (index <= total) {
int end = index + splitSize;
if (end > total) {
end = total;
}
List<WowMap> sublist = list.subList(index, end);
int effected = wowMapMapper.batchInsert(sublist);
if (effected == 0) {
throw new RuntimeException("sql effected 0 rows");
}
index += splitSize;
}
}
public void update(WowMap t) {
int effected = wowMapMapper.update(t);
if (effected == 0) {
throw new RuntimeException("sql effected 0 rows");
}
}
public void delete(String id) {
int effected = wowMapMapper.delete(id);
if (effected == 0) {
throw new RuntimeException("sql effected 0 rows");
}
}
public WowMap find(String id) {
WowMap wowMap = wowMapMapper.find(id);
return wowMap;
}
public PageList<WowMap> list(WowMapQueryParam queryParam) {
PageList<WowMap> pageList = new PageList<WowMap>();
int count = wowMapMapper.count(queryParam);
List<WowMap> list = wowMapMapper.list(queryParam);
pageList.setTotalCount(count);
pageList.setData(list);
pageList.setPageParam(queryParam.getPageParam());
return pageList;
}
}
另外,@Componet注解需要依赖spring-context包。还有我们写SQL的xml文件是资源文件,但为了方便查看编辑,我们直接把它放在了代码目录下,所以编译的时候不会被打包,需要在pom中添加配置如下:
</dependencies>
........
........
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
这样,我们的数据访问层逻辑就全部实现了。通过在RMS模块的controller中注入manager,即可实现对底层数据的访问。
二、controller层的实现
在com.idlewow.rms.controller包中,新建类MapController,在Contoller中,我们初步实现了对数据的增删查改。注意,这里list()方法,返回的字符串“/manage/map/list",代表视图所在路径,根据spring-mvc.xml中配置的视图路由解析规则,即返回/WEB-INF/views/manage/map/list.jsp页面。但如果在该方法上加上注解@ResponseBody,则代表直接返回该字符串,不会去寻找视图。在post方法中,我们就是直接返回数据的json串。代码如下:
package com.idlewow.rms.controller;
import com.idlewow.common.model.CommonResult;
import com.idlewow.common.model.PageList;
import com.idlewow.map.manager.WowMapManager;
import com.idlewow.map.model.WowMap;
import com.idlewow.query.model.WowMapQueryParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/manage/map")
public class MapController extends BaseController {
@Autowired
WowMapManager wowMapManager;
@RequestMapping("/list")
public Object list() {
return "/manage/map/list";
}
@ResponseBody
@RequestMapping(value = "/list", method = RequestMethod.POST)
public Object list(@RequestParam(value = "page", defaultValue = "1") int pageIndex, @RequestParam(value = "limit", defaultValue = "10") int pageSize, WowMapQueryParam queryParam) {
queryParam.setPage(pageIndex, pageSize);
PageList<WowMap> pageList = wowMapManager.list(queryParam);
return this.parseTable(pageList);
}
@RequestMapping("/add")
public Object add() {
return "/manage/map/add";
}
@ResponseBody
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Object add(@RequestBody WowMap wowMap) {
try {
wowMap.setCreateUser(this.currentUserName());
wowMapManager.insert(wowMap);
return CommonResult.success();
} catch (Exception ex) {
return CommonResult.fail();
}
}
@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
public Object edit(@PathVariable String id, Model model) {
WowMap wowMap = wowMapManager.find(id);
model.addAttribute(wowMap);
return "/manage/map/edit";
}
@ResponseBody
@RequestMapping(value = "/edit/{id}", method = RequestMethod.POST)
public Object edit(@PathVariable String id, @RequestBody WowMap wowMap) {
try {
if (!id.equals(wowMap.getId())) {
return CommonResult.fail("id不一致");
}
wowMap.setUpdateUser(this.currentUserName());
wowMapManager.update(wowMap);
return CommonResult.success();
} catch (Exception ex) {
return CommonResult.fail();
}
}
@ResponseBody
@RequestMapping(value = "/delete/{id}", method = RequestMethod.POST)
public Object delete(@PathVariable String id) {
try {
wowMapManager.delete(id);
return CommonResult.success();
} catch (Exception ex) {
return CommonResult.fail();
}
}
}
MapController.java
其中, CommonResult类是我定义的一个通用的结果返回类,PageList和PageParam是分页相关的辅助类,WowMapQueryParam是列表查询的参数类。
另外,前端列表展示使用了layui的datatable,需要给他返回对应的数据结构。因此,我们定义一个抽象类BaseController,实现对列表数据结构的转换,同时提供查询当前登录用户的方法。其他的Controller如无特殊情况均继承BaseController,代码如下:
package com.idlewow.rms.vo;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class LayuiDataTable<T> implements Serializable {
private Integer code;
private String message;
private Integer count;
private List<T> data;
}
LayuiDataTable.java
package com.idlewow.rms.controller;
import com.idlewow.admin.model.SysAdmin;
import com.idlewow.common.model.PageList;
import com.idlewow.rms.vo.LayuiDataTable;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.http.HttpSession;
public abstract class BaseController {
private static final String LoginUserKey = "loginuser";
@Autowired
protected HttpSession httpSession;
protected SysAdmin currentUser() {
return (SysAdmin) httpSession.getAttribute(LoginUserKey);
}
protected String currentUserName() {
return this.currentUser().getUsername();
}
protected LayuiDataTable parseTable(PageList pageList) {
LayuiDataTable dataTable = new LayuiDataTable();
dataTable.setMessage("读取成功");
dataTable.setCode(0);
dataTable.setCount(pageList.getTotalCount());
dataTable.setData(pageList.getData());
return dataTable;
}
}
BaseController.java
写完控制器,前端页面,我们直接套用x-admin的模板。在/WEB-INF/views/manage/map目录下,创建页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="/authorize.jsp" %>
<!DOCTYPE html>
<html class="x-admin-sm">
<head>
<meta charset="UTF-8">
<title>地图管理</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport"
content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi"/>
<link rel="stylesheet" href="<%=path%>/css/font.css">
<link rel="stylesheet" href="<%=path%>/css/xadmin.css">
<script type="text/javascript" src="<%=path%>/lib/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="<%=path%>/js/xadmin.js"></script>
</head>
<body>
<div class="x-nav">
<span class="layui-breadcrumb">
<a href="">首页</a>
<a href="">后台管理</a>
<a>
<cite>地图</cite></a>
</span>
<a class="layui-btn layui-btn-small" style="line-height:1.6em;margin-top:3px;float:right"
onclick="location.reload()" title="刷新">
<i class="layui-icon layui-icon-refresh" style="line-height:30px"></i></a>
</div>
<div class="layui-fluid">
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-body ">
<form id="queryForm" class="layui-form layui-col-space5" method="post">
<div class="layui-inline layui-show-xs-block">
<input type="text" name="name" placeholder="请输入地图名称" autocomplete="off" class="layui-input">
</div>
<div class="layui-inline layui-show-xs-block">
<button class="layui-btn" lay-submit lay-filter="search" type="button" onclick="search();">
<i class="layui-icon"></i>查询
</button>
</div>
<div class="layui-inline layui-show-xs-block">
<button class="layui-btn" type="button" onclick="reset();"> 重置</button>
</div>
<div class="layui-inline layui-show-xs-block">
<button type="button" class="layui-btn" onclick="xadmin.open('添加地图','add',500,500)">
<i class="layui-icon"></i>添加地图
</button>
</div>
<div class="layui-upload layui-inline layui-show-xs-block">
<button type="button" class="layui-btn layui-btn-normal" id="btnSelectFile">选择Excel</button>
<button type="button" class="layui-btn" id="btnImport">开始导入</button>
</div>
</form>
</div>
<div class="layui-card-body ">
<table class="layui-table layui-form" id="datatable"></table>
</div>
</div>
</div>
</div>
</div>
</body>
<script type="text/javascript" src="<%=path%>/js/helper.js?v=0530"></script>
<script type="text/javascript" src="<%=path%>/js/wow/manage/map/list.js?v=0530"></script>
</html>
list.jsp
<%@ page import="com.idlewow.rms.util.DropDownUtil" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="/authorize.jsp" %>
<!DOCTYPE html>
<html class="x-admin-sm">
<head>
<meta charset="UTF-8">
<title>编辑地图</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport"
content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi"/>
<link rel="stylesheet" href="<%=path%>/css/font.css">
<link rel="stylesheet" href="<%=path%>/css/xadmin.css">
<script type="text/javascript" src="<%=path%>/lib/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="<%=path%>/js/xadmin.js"></script>
</head>
<body>
<div class="layui-fluid">
<div class="layui-row">
<form:form class="layui-form" method="post" modelAttribute="wowMap">
<form:hidden path="id"/>
<div class="layui-form-item">
<form:label path="name" class="layui-form-label"> <span class="x-red">*</span>地图名称 </form:label>
<div class="layui-input-inline">
<form:input path="name" lay-verify="required" autocomplete="off" class="layui-input"/>
</div>
</div>
<div class="layui-form-item">
<form:label path="occupy" class="layui-form-label"> <span class="x-red">*</span>领土归属 </form:label>
<div class="layui-input-inline">
<form:select path="occupy" items="<%= DropDownUtil.OccupyMap %>"></form:select>
</div>
</div>
<div class="layui-form-item">
<form:label path="description" class="layui-form-label"> 地图描述 </form:label>
<div class="layui-input-inline">
<form:textarea path="description" class="layui-textarea"></form:textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"></label>
<div class="layui-input-inline">
<button class="layui-btn" lay-filter="edit" lay-submit type="button">修改</button>
</div>
</div>
</form:form>
</div>
</div>
<script type="text/javascript" src="<%=path%>/js/helper.js?v=0531"></script>
<script type="text/javascript" src="<%=path%>/js/wow/manage/map/edit.js?v=0510"></script>
</body>
</html>
edit.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="com.idlewow.rms.util.DropDownUtil" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ include file="/authorize.jsp" %>
<!DOCTYPE html>
<html class="x-admin-sm">
<head>
<meta charset="UTF-8">
<title>添加地图</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport"
content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi"/>
<link rel="stylesheet" href="<%=path%>/css/font.css">
<link rel="stylesheet" href="<%=path%>/css/xadmin.css">
<script type="text/javascript" src="<%=path%>/lib/layui/layui.js" charset="utf-8"></script>
<script type="text/javascript" src="<%=path%>/js/xadmin.js"></script>
</head>
<body>
<div class="layui-fluid">
<div class="layui-row">
<form class="layui-form" method="post">
<div class="layui-form-item">
<label for="name" class="layui-form-label"> <span class="x-red">*</span>地图名称 </label>
<div class="layui-input-inline">
<input type="text" id="name" name="name" required lay-verify="required"
autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label for="occupy" class="layui-form-label"> <span class="x-red">*</span>领土归属 </label>
<div class="layui-input-inline">
<% request.setAttribute("occupyMap", DropDownUtil.OccupyMap); %>
<select name="occupy" id="occupy">
<option value="">请选择领土归属</option>
<c:forEach items="${occupyMap}" var="item">
<option value="${item.key}">${item.value}</option>
</c:forEach>
</select>
</div>
</div>
<div class="layui-form-item">
<label for="description" class="layui-form-label"> 地图描述 </label>
<div class="layui-input-inline">
<textarea name="description" id="description" class="layui-textarea"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label"></label>
<div class="layui-input-inline">
<button class="layui-btn" lay-filter="add" lay-submit type="button">添加</button>
</div>
</div>
</form>
</div>
</div>
<script type="text/javascript" src="<%=path%>/js/helper.js?v=0531"></script>
<script type="text/javascript" src="<%=path%>/js/wow/manage/map/add.js?v=0531"></script>
</body>
</html>
add.jsp
在/js/wow/manage/map目录下,创建相应的js脚本:
layui.use(['upload', 'table', 'form'], function () {
var table = layui.table;
table.render({
elem: '#datatable'
, url: '/manage/map/list'
, method: 'post'
, cellMinWidth: 80
, cols: [[
{field: 'id', width: 50, title: 'id'}
, {field: 'name', title: '地图名称'}
, {
field: 'occupy', title: '领土归属', templet: function (d) {
return enumUtil.occupyImage(d.occupy) + enumUtil.occupy(d.occupy);
}
}
, {
title: '操作', templet: function (d) {
return '<button class="layui-btn layui-btn-xs" onclick="xadmin.open(\'编辑地图\',\'edit/' + d.id + '\', 500, 500)" type="button"><i class="layui-icon"></i>编辑</button>' +
'<button class="layui-btn-danger layui-btn layui-btn-xs" onclick="remove(this, \'' + d.id + '\')" type="button"><i class="layui-icon"></i>删除</button>';
}
}
]]
, page: {
layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局
, limits: [10, 20, 30, 40, 50]
, groups: 3 //只显示 1 个连续页码
, first: '首页'
, last: '尾页'
}
});
});
function search() {
var table = layui.table;
table.reload('datatable', {
where: {
name: $('input[name="name"]').val()
},
page: {
curr: 1
}
});
}
function reset(){
$('#queryForm').reset();
}
function remove(obj, id) {
layer.confirm('确认要删除吗?', function () {
$.ajax({
url: '/manage/map/delete/' + id,
type: 'post',
success: function (result) {
if (result.code === 1) {
$(obj).parents("tr").remove();
layer.msg('删除成功', {icon: 1, time: 1000});
} else {
layer.alert("删除失败", {icon: 5});
}
},
error: function () {
layer.alert("请求失败", {icon: 5});
}
});
});
}
list.js
layui.use(['form', 'layer'],
function () {
var form = layui.form;
form.render();
form.verify({});
form.on('submit(edit)',
function (data) {
$.ajax({
url: '/manage/map/edit/' + data.field.id,
type: 'post',
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data.field),
success: function (result) {
if (result.code === 1) {
layer.alert(result.message, {icon: 6},
function () {
xadmin.close();
xadmin.father_reload();
});
} else {
layer.alert(result.message, {icon: 5});
}
},
error: function () {
layer.alert("请求失败", {icon: 5});
}
});
});
});
edit.js
layui.use(['form', 'layer'],
function () {
var form = layui.form;
form.verify({});
form.on('submit(add)',
function (data) {
$.ajax({
url: '/manage/map/add',
type: 'post',
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data.field),
success: function (result) {
if (result.code === 1) {
layer.alert(result.message, {icon: 6},
function () {
xadmin.close();
xadmin.father_reload();
});
} else {
layer.alert(result.message, {icon: 5});
}
},
error: function () {
layer.alert("请求失败", {icon: 5});
}
});
});
});
add.js
三、项目启动
本次,我们修改了facade和core项目,这两个项目是作为jar包被rms模块引用的,因此必须先将其编译打包,这里我们用第(二)章定义的打包命令直接将整个项目重新打包。以后凡是jar包项目有改动,我们启动web项目前,都先重新打包一遍。
另外,maven的编译插件可能默认的jdk版本是1.5,我们在pom中配置一下,配成1.8,配置如下:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
…………
…………
</plugins>
</build>
OK,全部搞定之后,我们运行一下,看下效果:
小结
本章,我们初步实现了后台管理系统数据配置的增删查改,但还有很多功能不完善。
比如,添加、编辑时的数据没有进行校验;单个录入数据太麻烦,想要通过excel批量录入;出现异常时缺乏相应的日志记录,等等。
这些内容,我们都将在后面的章节中持续完善。
本章源码下载地址:https://idlestudio.ctfile.com/fs/14960372-383560985