文章模块,方便举例说明

This commit is contained in:
Heeexy
2017-11-18 13:49:06 +08:00
parent 4e8a8845fb
commit 9af5fb8deb
19 changed files with 297 additions and 356 deletions
+20
View File
@@ -1,3 +1,23 @@
# SpringBoot-shiro-vue
提供一套基于SpringBoot-shiro-vue的权限管理思路.前后端都加以控制,做到按钮/接口级别的权限
# 设计思路
### 核心
每个登录用户拥有各自的N条**权限**,比如文章:查看/编辑/发布/删除
### 后端
基于 [RABC新解](http://globeeip.iteye.com/blog/1236167) .
用户--角色--权限
后台接口只验证**权限**,不看角色.
角色的作用其实只是用来管理分配权限的,真正的验证只验证**权限** ,而不去管你是否是那种角色.体现在代码上就是接口上注解为```@RequiresPermissions("writer:list")``` ```@RequiresPermissions("writer:update")```
而不是验证```@RequiresRoles(...)```
### 前端
@@ -0,0 +1,61 @@
package com.heeexy.example.controller;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.service.ArticleService;
import com.heeexy.example.util.CommonUtil;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
* @author: hxy
* @description: 文章相关Controller
* @date: 2017/10/24 16:04
*/
@RestController
@RequestMapping("/article")
public class ArticleController {
@Autowired
private ArticleService articleService;
/**
* 查询文章列表
*
* @param request
* @return
*/
@RequiresPermissions("article:list")
@GetMapping("/listArticle")
public JSONObject listArticle(HttpServletRequest request) {
return articleService.listArticle(CommonUtil.request2Json(request));
}
/**
* 新增文章
*
* @param requestJson
* @return
*/
@RequiresPermissions("article:add")
@PostMapping("/addArticle")
public JSONObject addArticle(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "content");
return articleService.addArticle(requestJson);
}
/**
* 修改文章
*
* @param requestJson
* @return
*/
@RequiresPermissions("article:update")
@PostMapping("/updateArticle")
public JSONObject updateArticle(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "id,content");
return articleService.updateArticle(requestJson);
}
}
@@ -1,72 +0,0 @@
package com.heeexy.example.controller;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.service.WriterService;
import com.heeexy.example.util.CommonUtil;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
* @author: hxy
* @description: 作者相关Controller
* @date: 2017/10/24 16:04
*/
@RestController
@RequestMapping("/writer")
public class WriterController {
@Autowired
private WriterService writerService;
/**
* 查询作者列表
*
* @param request
* @return
*/
@RequiresPermissions("writer:list")
@GetMapping("/listWriter")
public JSONObject listWriter(HttpServletRequest request) {
return writerService.listWriter(CommonUtil.request2Json(request));
}
/**
* 新增作者
*
* @param requestJson
* @return
*/
@RequiresPermissions("writer:add")
@PostMapping("/addWriter")
public JSONObject addWriter(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "writerName");
return writerService.addWriter(requestJson);
}
/**
* 修改作者
*
* @param requestJson
* @return
*/
@RequiresPermissions("writer:update")
@PostMapping("/updateWriter")
public JSONObject updateWriter(@RequestBody JSONObject requestJson) {
CommonUtil.hasAllRequired(requestJson, "writerId,writerName");
return writerService.updateWriter(requestJson);
}
/**
* 根据发布ID查询信息
*
* @param writerId
* @return JSONObject
*/
@GetMapping("/getWriterById")
public JSONObject getWriterById(String writerId) {
return writerService.getWriterById(writerId);
}
}
@@ -0,0 +1,44 @@
package com.heeexy.example.dao;
import com.alibaba.fastjson.JSONObject;
import java.util.List;
/**
* @author: hxy
* @description: 文章Dao层
* @date: 2017/10/24 16:06
*/
public interface ArticleDao {
/**
* 新增文章
*
* @param jsonObject
* @return
*/
int addArticle(JSONObject jsonObject);
/**
* 统计文章总数
*
* @param jsonObject
* @return
*/
int countArticle(JSONObject jsonObject);
/**
* 文章列表
*
* @param jsonObject
* @return
*/
List<JSONObject> listArticle(JSONObject jsonObject);
/**
* 更新文章
*
* @param jsonObject
* @return
*/
int updateArticle(JSONObject jsonObject);
}
@@ -1,52 +0,0 @@
package com.heeexy.example.dao;
import com.alibaba.fastjson.JSONObject;
import java.util.List;
/**
* @author: hxy
* @description: 作者Dao层
* @date: 2017/10/24 16:06
*/
public interface WriterDao {
/**
* 新增作者
*
* @param jsonObject
* @return
*/
int addWriter(JSONObject jsonObject);
/**
* 统计作者总数
*
* @param jsonObject
* @return
*/
int countWriter(JSONObject jsonObject);
/**
* 作者列表
*
* @param jsonObject
* @return
*/
List<JSONObject> listWriter(JSONObject jsonObject);
/**
* 更新作者
*
* @param jsonObject
* @return
*/
int updateWriter(JSONObject jsonObject);
/**
* 根据发布ID查询信息
*
* @param writerId
* @return JSONObject
*/
JSONObject getWriterById(String writerId);
}
@@ -0,0 +1,33 @@
package com.heeexy.example.service;
import com.alibaba.fastjson.JSONObject;
/**
* @author: hxy
* @date: 2017/10/24 16:06
*/
public interface ArticleService {
/**
* 新增文章
*
* @param jsonObject
* @return
*/
JSONObject addArticle(JSONObject jsonObject);
/**
* 文章列表
*
* @param jsonObject
* @return
*/
JSONObject listArticle(JSONObject jsonObject);
/**
* 更新文章
*
* @param jsonObject
* @return
*/
JSONObject updateArticle(JSONObject jsonObject);
}
@@ -1,41 +0,0 @@
package com.heeexy.example.service;
import com.alibaba.fastjson.JSONObject;
/**
* @author: hxy
* @date: 2017/10/24 16:06
*/
public interface WriterService {
/**
* 新增作者
*
* @param jsonObject
* @return
*/
JSONObject addWriter(JSONObject jsonObject);
/**
* 作者列表
*
* @param jsonObject
* @return
*/
JSONObject listWriter(JSONObject jsonObject);
/**
* 更新作者
*
* @param jsonObject
* @return
*/
JSONObject updateWriter(JSONObject jsonObject);
/**
* 根据发布ID查询信息
*
* @param writerId
* @return JSONObject
*/
JSONObject getWriterById(String writerId);
}
@@ -0,0 +1,63 @@
package com.heeexy.example.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.dao.ArticleDao;
import com.heeexy.example.service.ArticleService;
import com.heeexy.example.util.CommonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* @author: hxy
* @description:
* @date: 2017/10/24 16:07
*/
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleDao articleDao;
/**
* 新增文章
*
* @param jsonObject
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public JSONObject addArticle(JSONObject jsonObject) {
articleDao.addArticle(jsonObject);
return CommonUtil.successJson();
}
/**
* 文章列表
*
* @param jsonObject
* @return
*/
@Override
public JSONObject listArticle(JSONObject jsonObject) {
CommonUtil.fillPageParam(jsonObject);
int count = articleDao.countArticle(jsonObject);
List<JSONObject> list = articleDao.listArticle(jsonObject);
return CommonUtil.successPage(jsonObject, list, count);
}
/**
* 更新文章
*
* @param jsonObject
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public JSONObject updateArticle(JSONObject jsonObject) {
articleDao.updateArticle(jsonObject);
return CommonUtil.successJson();
}
}
@@ -1,86 +0,0 @@
package com.heeexy.example.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.heeexy.example.config.exception.CommonJsonException;
import com.heeexy.example.dao.WriterDao;
import com.heeexy.example.service.WriterService;
import com.heeexy.example.util.CommonUtil;
import com.heeexy.example.util.RandomUtil;
import com.heeexy.example.util.constants.ErrorEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.util.List;
/**
* @author: hxy
* @description:
* @date: 2017/10/24 16:07
*/
@Service
public class WriterServiceImpl implements WriterService {
@Autowired
private WriterDao writerDao;
/**
* 新增作者
*
* @param jsonObject
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public JSONObject addWriter(JSONObject jsonObject) {
String writerId = RandomUtil.genarateId("");
jsonObject.put("writerId", writerId);
writerDao.addWriter(jsonObject);
return CommonUtil.successJson();
}
/**
* 作者列表
*
* @param jsonObject
* @return
*/
@Override
public JSONObject listWriter(JSONObject jsonObject) {
CommonUtil.fillPageParam(jsonObject);
int count = writerDao.countWriter(jsonObject);
List<JSONObject> list = writerDao.listWriter(jsonObject);
return CommonUtil.successPage(jsonObject, list, count);
}
/**
* 更新作者
*
* @param jsonObject
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public JSONObject updateWriter(JSONObject jsonObject) {
int i = writerDao.updateWriter(jsonObject);
if (i == 1) {
return CommonUtil.successJson();
} else {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw new CommonJsonException(ErrorEnum.E_602);
}
}
/**
* 根据发布ID查询信息
*
* @param writerId
* @return JSONObject
*/
@Override
public JSONObject getWriterById(String writerId) {
JSONObject jsonObject = writerDao.getWriterById(writerId);
return CommonUtil.successJson(jsonObject);
}
}
@@ -13,8 +13,6 @@ public enum ErrorEnum {
E_501("501", "请求路径不存在"),
E_502("502", "权限不足"),
E_602("602", "数据更新失败"),
E_20011("20011", "登陆已过期,请重新登陆"),
E_90003("90003", "缺少必填参数");
+1 -1
View File
@@ -64,6 +64,6 @@
<logger name="org.springframework" level="WARN"/>
<logger name="org.apache" level="WARN"/>
<!--如果需要打印SQL,可以把下面的级别设置为DEBUG -->
<logger name="com.heeexy.example.biz" level="DEBUG"/>
<logger name="com.heeexy.example.dao" level="DEBUG"/>
</configuration>
@@ -0,0 +1,36 @@
<?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.heeexy.example.dao.ArticleDao">
<insert id="addArticle" parameterType="com.alibaba.fastjson.JSONObject">
INSERT INTO article
(content) VALUES
( #{content})
</insert>
<select id="countArticle" resultType="Integer">
SELECT count(0)
FROM article w
WHERE w.delete_status = '1'
</select>
<select id="listArticle" resultType="com.alibaba.fastjson.JSONObject">
SELECT
w.id id,
w.content content,
date_format(w.create_time, '%Y-%m-%d') createTime
FROM article w
WHERE w.delete_status = '1'
ORDER BY w.id DESC
LIMIT #{offSet}, #{pageRow}
</select>
<update id="updateArticle" parameterType="com.alibaba.fastjson.JSONObject">
UPDATE article
SET
content = #{content}
WHERE id = #{id}
</update>
</mapper>
@@ -15,5 +15,4 @@
AND u.password = #{password}
</select>
</mapper>
@@ -17,20 +17,19 @@
</resultMap>
<select id="getUserPermission" resultMap="permissionMap">
SELECT
u.id userId,
u.nickname nickname,
u.role_id roleId,
r.role_name roleName,
p.menu_code menuCode,
p.permission_code permissionCode
u.id userId,
u.nickname nickname,
u.role_id roleId,
r.role_name roleName,
p.menu_code menuCode,
p.permission_code permissionCode
FROM sys_user u
LEFT JOIN sys_role r ON r.id = u.role_id
LEFT JOIN sys_role_permission rp ON u.role_id = rp.role_id
LEFT JOIN sys_permission p ON rp.permission_id = p.id
LEFT JOIN sys_role r ON r.id = u.role_id
LEFT JOIN sys_role_permission rp ON u.role_id = rp.role_id
LEFT JOIN sys_permission p ON rp.permission_id = p.id
WHERE u.username = #{username}
</select>
<select id="getAllPermission" resultType="String">
SELECT p.permission_code permissionCode
FROM sys_permission p
@@ -1,44 +0,0 @@
<?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.heeexy.example.dao.WriterDao">
<insert id="addWriter" parameterType="com.alibaba.fastjson.JSONObject">
INSERT INTO writer
(writer_id, writer_name) VALUES
(#{writerId}, #{writerName})
</insert>
<select id="countWriter" resultType="Integer">
SELECT count(0)
FROM writer w
WHERE w.delete_status = '1'
</select>
<select id="listWriter" resultType="com.alibaba.fastjson.JSONObject">
SELECT
w.writer_id writerId,
w.writer_name writerName,
date_format(w.create_time, '%Y-%m-%d') createTime
FROM writer w
WHERE w.delete_status = '1'
ORDER BY w.id DESC
LIMIT #{offSet}, #{pageRow}
</select>
<update id="updateWriter" parameterType="com.alibaba.fastjson.JSONObject">
UPDATE writer
SET
writer_name = #{writerName}
WHERE writer.writer_id = #{writerId}
</update>
<select id="getWriterById" parameterType="java.lang.String" resultType="com.alibaba.fastjson.JSONObject">
SELECT
w.writer_id writerId,
w.writer_name writerName,
date_format(w.create_time, '%Y-%m-%d') createTime
FROM writer w
WHERE w.delete_status = '1' AND w.writer_id = #{writerId}
</select>
</mapper>
-6
View File
@@ -1,6 +0,0 @@
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+1 -1
View File
@@ -39,7 +39,7 @@ export const asyncRouterMap = [
name: '功能模块',
icon: 'system',
children: [
{path: 'writer', component: _import('writer/writer'), name: '作家', menu: 'writer'},
{path: 'article', component: _import('article/article'), name: '文章', menu: 'article'},
]
},
{
+1 -1
View File
@@ -53,7 +53,7 @@ const permission = {
GenerateRoutes({commit}, userPermission) {
//生成路由
return new Promise(resolve => {
//roles是后台传过来的角色数组,比如['管理员','作家']
//roles是后台传过来的角色数组,比如['管理员','文章']
const role = userPermission.roleName;
const menus = userPermission.menuList;
//声明 该角色可用的路由
@@ -3,11 +3,7 @@
<div class="filter-container">
<el-form>
<el-form-item>
<el-input @keyup.enter.native="handleFilter" style="width: 200px;" placeholder="作家名称"
v-model="listQuery.name">
</el-input>
<el-button type="primary" icon="search" @click="handleFilter()">搜索</el-button>
<el-button type="primary" icon="plus" @click="showCreate" v-if="hasPerm('writer:add')">添加
<el-button type="primary" icon="plus" @click="showCreate" v-if="hasPerm('article:add')">添加
</el-button>
</el-form-item>
</el-form>
@@ -19,13 +15,13 @@
<span v-text="getIndex(scope.$index)"> </span>
</template>
</el-table-column>
<el-table-column align="center" prop="writerName" label="作家" style="width: 60px;"></el-table-column>
<el-table-column align="center" prop="content" label="文章" style="width: 60px;"></el-table-column>
<el-table-column align="center" label="创建时间" width="170">
<template scope="scope">
<span>{{scope.row.createTime}}</span>
</template>
</el-table-column>
<el-table-column align="center" label="管理" width="200" v-if="hasPerm('writer:update')">
<el-table-column align="center" label="管理" width="200" v-if="hasPerm('article:update')">
<template scope="scope">
<el-button type="primary" icon="edit" @click="showUpdate(scope.$index)">修改</el-button>
</template>
@@ -41,17 +37,17 @@
layout="total, sizes, prev, pager, next, jumper">
</el-pagination>
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
<el-form class="small-space" :model="tempWriter" label-position="left" label-width="60px"
<el-form class="small-space" :model="tempArticle" label-position="left" label-width="60px"
style='width: 300px; margin-left:50px;'>
<el-form-item label="名称">
<el-input type="text" v-model="tempWriter.writerName">
<el-form-item label="文章">
<el-input type="text" v-model="tempArticle.content">
</el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button v-if="dialogStatus=='create'" type="success" @click="createWriter">创 建</el-button>
<el-button type="primary" v-else @click="updateWriter">修 改</el-button>
<el-button v-if="dialogStatus=='create'" type="success" @click="createArticle">创 建</el-button>
<el-button type="primary" v-else @click="updateArticle">修 改</el-button>
</div>
</el-dialog>
</div>
@@ -72,11 +68,11 @@
dialogFormVisible: false,
textMap: {
update: '编辑',
create: '创建作家'
create: '创建文章'
},
tempWriter: {
writerName: "",
writerId: ""
tempArticle: {
id: "",
content: ""
}
}
},
@@ -86,12 +82,12 @@
methods: {
getList() {
//查询列表
if (!this.hasPerm('writer:list')) {
if (!this.hasPerm('article:list')) {
return
}
this.listLoading = true;
this.api({
url: "/writer/listWriter",
url: "/article/listArticle",
method: "get",
params: this.listQuery
}).then(data => {
@@ -110,52 +106,45 @@
this.listQuery.pageNum = val
this.getList();
},
handleFilter() {
//查询事件
this.listQuery.pageNum = 1
this.getList()
},
getIndex($index) {
//表格序号
return (this.listQuery.pageNum - 1) * this.listQuery.pageRow + $index + 1
},
showCreate() {
//显示新增对话框
this.tempWriter.writerId = "";
this.tempWriter.writerName = "";
this.tempArticle.content = "";
this.dialogStatus = "create"
this.dialogFormVisible = true
},
showUpdate($index) {
//显示新增对话框
this.tempWriter.writerId = this.list[$index].writerId;
this.tempWriter.writerName = this.list[$index].writerName;
//显示修改对话框
this.tempArticle.id = this.list[$index].id;
this.tempArticle.content = this.list[$index].content;
this.dialogStatus = "update"
this.dialogFormVisible = true
},
createWriter() {
//保存新作家
createArticle() {
//保存新文章
this.api({
url: "/writer/addWriter",
url: "/article/addArticle",
method: "post",
data: this.tempWriter
}).then(data => {
data: this.tempArticle
}).then(() => {
this.getList();
this.dialogFormVisible = false
})
},
updateWriter() {
//修改作家
updateArticle() {
//修改文章
this.api({
url: "/writer/updateWriter",
url: "/article/updateArticle",
method: "post",
data: this.tempWriter
}).then(data => {
data: this.tempArticle
}).then(() => {
this.getList();
this.dialogFormVisible = false
})
},
}
}
</script>