业务系统
litemall开源商城
dbblog开源博客
2024最新同城上门家政按摩H5小程序源码 | 全开源无需授权【安装教程】
MES智能制造、WMS仓储管理、TMS运维管理
智能农业
智慧食堂
智慧工地
本文档使用 MrDoc 发布
-
+
首页
litemall开源商城
开源地址:https://gitee.com/linlinjava/litemall?_from=gitee_search > litemall = Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端 + Vue用户移动端 ## 项目架构:  >i 主要关注一下 1增、2删、3改、4查、5封装(数据统一返回、异常是否封装)、6其他技术方面 ## 1、增 - 表单请求: ~~~ createData() { this.$refs['dataForm'].validate(valid => { if (valid) { createCategory(this.dataForm) .then(response => { this.getList() // 更新L1目录 this.getCatL1() this.dialogFormVisible = fals e this.$notify.success({ title: '成功', message: '创建成功' }) }) .catch(response => { this.$notify.error({ title: '失败', message: response.data.errmsg }) }) } }) }, ~~~ - 使用的axios发送请求 ~~~ export function createCategory(data) { return request({ url: '/category/create', method: 'post', data }) } ~~~ - dto接收数据 ```java @RequiresPermissions("admin:category:create") @RequiresPermissionsDesc(menu = {"商场管理", "类目管理"}, button = "添加") @PostMapping("/create") public Object create(@RequestBody LitemallCategory category) { Object error = validate(category); if (error != null) { return error; } categoryService.add(category); return ResponseUtil.ok(category); } ``` - 使用mapper的xml进行了数据的插入 ~~~ <insert id="insertSelective" parameterType="org.linlinjava.litemall.db.domain.LitemallCategory"> <!-- WARNING - @mbg.generated This element is automatically generated by MyBatis Generator, do not modify. --> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID() </selectKey> insert into litemall_category <trim prefix="(" suffix=")" suffixOverrides=","> <if test="name != null"> `name`, </if> <if test="keywords != null"> keywords, </if> <if test="desc != null"> `desc`, </if> <if test="pid != null"> pid, </if> <if test="iconUrl != null"> icon_url, </if> <if test="picUrl != null"> pic_url, </if> <if test="level != null"> `level`, </if> <if test="sortOrder != null"> sort_order, </if> <if test="addTime != null"> add_time, </if> <if test="updateTime != null"> update_time, </if> <if test="deleted != null"> deleted, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides=","> <if test="name != null"> #{name,jdbcType=VARCHAR}, </if> <if test="keywords != null"> #{keywords,jdbcType=VARCHAR}, </if> <if test="desc != null"> #{desc,jdbcType=VARCHAR}, </if> <if test="pid != null"> #{pid,jdbcType=INTEGER}, </if> <if test="iconUrl != null"> #{iconUrl,jdbcType=VARCHAR}, </if> <if test="picUrl != null"> #{picUrl,jdbcType=VARCHAR}, </if> <if test="level != null"> #{level,jdbcType=VARCHAR}, </if> <if test="sortOrder != null"> #{sortOrder,jdbcType=TINYINT}, </if> <if test="addTime != null"> #{addTime,jdbcType=TIMESTAMP}, </if> <if test="updateTime != null"> #{updateTime,jdbcType=TIMESTAMP}, </if> <if test="deleted != null"> #{deleted,jdbcType=BIT}, </if> </trim> </insert> ~~~ ## 2、删 - 前端请求 ~~~ handleDelete(row) { deleteCategory(row) .then(response => { this.getList() // 更新L1目录 this.getCatL1() this.$notify.success({ title: '成功', message: '删除成功' }) }) .catch(response => { this.$notify.error({ title: '失败', message: response.data.errmsg }) }) } ~~~ - api ~~~ export function deleteCategory(data) { return request({ url: '/category/delete', method: 'post', data }) } ~~~ - 后端处理 ~~~ @RequiresPermissions("admin:category:delete") @RequiresPermissionsDesc(menu = {"商场管理", "类目管理"}, button = "删除") @PostMapping("/delete") public Object delete(@RequestBody LitemallCategory category) { Integer id = category.getId(); if (id == null) { return ResponseUtil.badArgument(); } categoryService.deleteById(id); return ResponseUtil.ok(); } ~~~ service层: ~~~ public void deleteById(Integer id) { categoryMapper.logicalDeleteByPrimaryKey(id); } ~~~ mapper层: ~~~ <update id="logicalDeleteByPrimaryKey" parameterType="java.lang.Integer"> <!-- WARNING - @mbg.generated This element is automatically generated by MyBatis Generator, do not modify. --> update litemall_category set deleted = 1 where id = #{id,jdbcType=INTEGER} </update> ~~~ ## 3、改 ~~~ updateData() { this.$refs['dataForm'].validate(valid => { if (valid) { updateCategory(this.dataForm) .then(() => { this.getList() // 更新L1目录 this.getCatL1() this.dialogFormVisible = false this.$notify.success({ title: '成功', message: '更新成功' }) }) .catch(response => { this.$notify.error({ title: '失败', message: response.data.errmsg }) }) } }) }, ~~~ - api ~~~ export function updateCategory(data) { return request({ url: '/category/update', method: 'post', data }) } ~~~ - 后端处理 ~~~ @RequiresPermissions("admin:category:update") @RequiresPermissionsDesc(menu = {"商场管理", "类目管理"}, button = "编辑") @PostMapping("/update") public Object update(@RequestBody LitemallCategory category) { Object error = validate(category); if (error != null) { return error; } if (categoryService.updateById(category) == 0) { return ResponseUtil.updatedDataFailed(); } return ResponseUtil.ok(); } ~~~ - service ~~~ public int updateById(LitemallCategory category) { category.setUpdateTime(LocalDateTime.now()); return categoryMapper.updateByPrimaryKeySelective(category); } ~~~ - mapper接口 `int updateByPrimaryKeySelective(LitemallCategory record);` - mapper实现 ~~~ <update id="updateByPrimaryKeySelective" parameterType="org.linlinjava.litemall.db.domain.LitemallCategory"> <!-- WARNING - @mbg.generated This element is automatically generated by MyBatis Generator, do not modify. --> update litemall_category <set> <if test="name != null"> `name` = #{name,jdbcType=VARCHAR}, </if> <if test="keywords != null"> keywords = #{keywords,jdbcType=VARCHAR}, </if> <if test="desc != null"> `desc` = #{desc,jdbcType=VARCHAR}, </if> <if test="pid != null"> pid = #{pid,jdbcType=INTEGER}, </if> <if test="iconUrl != null"> icon_url = #{iconUrl,jdbcType=VARCHAR}, </if> <if test="picUrl != null"> pic_url = #{picUrl,jdbcType=VARCHAR}, </if> <if test="level != null"> `level` = #{level,jdbcType=VARCHAR}, </if> <if test="sortOrder != null"> sort_order = #{sortOrder,jdbcType=TINYINT}, </if> <if test="addTime != null"> add_time = #{addTime,jdbcType=TIMESTAMP}, </if> <if test="updateTime != null"> update_time = #{updateTime,jdbcType=TIMESTAMP}, </if> <if test="deleted != null"> deleted = #{deleted,jdbcType=BIT}, </if> </set> where id = #{id,jdbcType=INTEGER} </update> ~~~ ## 4、查 - 查询结果放到el-table里面 ~~~ <el-table v-loading="listLoading" :data="list" element-loading-text="正在查询中。。。" border fit highlight-current-row> <el-table-column align="center" label="管理员ID" prop="id" sortable /> <el-table-column align="center" label="管理员名称" prop="username" /> <el-table-column align="center" label="管理员头像" prop="avatar"> <template slot-scope="scope"> <img v-if="scope.row.avatar" :src="scope.row.avatar" width="40"> </template> </el-table-column> <el-table-column align="center" label="管理员角色" prop="roleIds"> <template slot-scope="scope"> <el-tag v-for="roleId in scope.row.roleIds" :key="roleId" type="primary" style="margin-right: 20px;"> {{ formatRole(roleId) }} </el-tag> </template> </el-table-column> <el-table-column align="center" label="操作" class-name="small-padding fixed-width"> <template slot-scope="scope"> <el-button v-permission="['POST /admin/admin/update']" type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button> <el-button v-permission="['POST /admin/admin/delete']" type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button> </template> </el-table-column> </el-table> ~~~ ==vue中 v-bind=“$props“和v-bind=“$attrs“的理解和使用方式== 使用了PageHelper.startPage进行分页 ~~~ PageHelper.startPage(page, size); return userMapper.selectByExample(example); ~~~ - 在mapper中 查询之前进行拦截,进行分页。 ==疑问,对于 复杂的联合查询,分页的数据能准确吗?== ## 5、封装 - 请求后端的时候带上token ~~~js service.interceptors.request.use( config => { // Do something before request is sent if (store.getters.token) { // 让每个请求携带token-- ['X-Litemall-Admin-Token']为自定义key 请根据实际情况自行修改 config.headers['X-Litemall-Admin-Token'] = getToken() } return config }, error => { // Do something with request error console.log(error) // for debug Promise.reject(error) } ) ~~~ - 同时做了代码拦截 ~~~ // response interceptor service.interceptors.response.use( response => { const res = response.data if (res.errno === 501) { MessageBox.alert('系统未登录,请重新登录', '错误', { confirmButtonText: '确定', type: 'error' }).then(() => { store.dispatch('FedLogOut').then(() => { location.reload() }) }) return Promise.reject('error') } else if (res.errno === 502) { MessageBox.alert('系统内部错误,请联系管理员维护', '错误', { confirmButtonText: '确定', type: 'error' }) return Promise.reject('error') } else if (res.errno === 503) { MessageBox.alert('请求业务目前未支持', '警告', { confirmButtonText: '确定', type: 'error' }) return Promise.reject('error') } else if (res.errno === 504) { MessageBox.alert('更新数据已经失效,请刷新页面重新操作', '警告', { confirmButtonText: '确定', type: 'error' }) return Promise.reject('error') } else if (res.errno === 505) { MessageBox.alert('更新失败,请再尝试一次', '警告', { confirmButtonText: '确定', type: 'error' }) return Promise.reject('error') } else if (res.errno === 506) { MessageBox.alert('没有操作权限,请联系管理员授权', '错误', { confirmButtonText: '确定', type: 'error' }) return Promise.reject('error') } else if (res.errno !== 0) { // 非5xx的错误属于业务错误,留给具体页面处理 return Promise.reject(response) } else { return response } }, error => { console.log('err' + error)// for debug Message({ message: '登录连接超时(后台不能连接,请联系系统管理员)', type: 'error', duration: 5 * 1000 }) return Promise.reject(error) }) ~~~ - 统一返回了:Object 使用 ResponseUtil.ok方法统一处理 代码如下: ~~~java /** * 响应操作结果 * <pre> * { * errno: 错误码, * errmsg:错误消息, * data: 响应数据 * } * </pre> * * <p> * 错误码: * <ul> * <li> 0,成功; * <li> 4xx,前端错误,说明前端开发者需要重新了解后端接口使用规范: * <ul> * <li> 401,参数错误,即前端没有传递后端需要的参数; * <li> 402,参数值错误,即前端传递的参数值不符合后端接收范围。 * </ul> * <li> 5xx,后端错误,除501外,说明后端开发者应该继续优化代码,尽量避免返回后端错误码: * <ul> * <li> 501,验证失败,即后端要求用户登录; * <li> 502,系统内部错误,即没有合适命名的后端内部错误; * <li> 503,业务不支持,即后端虽然定义了接口,但是还没有实现功能; * <li> 504,更新数据失效,即后端采用了乐观锁更新,而并发更新时存在数据更新失效; * <li> 505,更新数据失败,即后端数据库更新失败(正常情况应该更新成功)。 * </ul> * <li> 6xx,小商城后端业务错误码, * 具体见litemall-admin-api模块的AdminResponseCode。 * <li> 7xx,管理后台后端业务错误码, * 具体见litemall-wx-api模块的WxResponseCode。 * </ul> */ public class ResponseUtil { public static Object ok() { Map<String, Object> obj = new HashMap<String, Object>(); obj.put("errno", 0); obj.put("errmsg", "成功"); return obj; } public static Object ok(Object data) { Map<String, Object> obj = new HashMap<String, Object>(); obj.put("errno", 0); obj.put("errmsg", "成功"); obj.put("data", data); return obj; } public static Object okList(List list) { Map<String, Object> data = new HashMap<String, Object>(); data.put("list", list); if (list instanceof Page) { Page page = (Page) list; data.put("total", page.getTotal()); data.put("page", page.getPageNum()); data.put("limit", page.getPageSize()); data.put("pages", page.getPages()); } else { data.put("total", list.size()); data.put("page", 1); data.put("limit", list.size()); data.put("pages", 1); } return ok(data); } public static Object okList(List list, List pagedList) { Map<String, Object> data = new HashMap<String, Object>(); data.put("list", list); if (pagedList instanceof Page) { Page page = (Page) pagedList; data.put("total", page.getTotal()); data.put("page", page.getPageNum()); data.put("limit", page.getPageSize()); data.put("pages", page.getPages()); } else { data.put("total", pagedList.size()); data.put("page", 1); data.put("limit", pagedList.size()); data.put("pages", 1); } return ok(data); } public static Object fail() { Map<String, Object> obj = new HashMap<String, Object>(); obj.put("errno", -1); obj.put("errmsg", "错误"); return obj; } public static Object fail(int errno, String errmsg) { Map<String, Object> obj = new HashMap<String, Object>(); obj.put("errno", errno); obj.put("errmsg", errmsg); return obj; } public static Object fail(int errno, String errmsg, String data) { Map<String, Object> obj = new HashMap<String, Object>(3); obj.put("errno", errno); obj.put("errmsg", errmsg); obj.put("data", data); return obj; } public static Object badArgument() { return fail(401, "参数不对"); } public static Object badArgumentValue() { return fail(402, "参数值不对"); } public static Object unlogin() { return fail(501, "请登录"); } public static Object serious() { return fail(502, "系统内部错误"); } public static Object unsupport() { return fail(503, "业务不支持"); } public static Object updatedDateExpired() { return fail(504, "更新数据已经失效"); } public static Object updatedDataFailed() { return fail(505, "更新数据失败"); } public static Object unauthz() { return fail(506, "无操作权限"); } } ~~~ - 在service层 使用以下的方式 截断请求,没有对异常进行封装 ~~~ return ResponseUtil.badArgument(); return ResponseUtil.fail(GOODS_NAME_EXIST, "商品名已经存在"); throw new RuntimeException("更新数据失败"); ~~~ ## 6、其他技术 暂无
superadmin
2023年10月15日 17:00
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码