用户&角色&权限demo_case 梳理总结
用户&角色&权限demo_case小结
实现过程问题记录
Q1:
1- UserMapper中sql语句查询结果和实体类不一致
TODO:目前查询筛选数据和实体类不一致???
2- 多表查询配置Role中的column无查询的id
验证结果,查询效果一致,分析:对于sql语句未查询到的字段,实体类中未默认值
Q2:
角色前端界面不显示数据,后端能反馈数据
前端界面显示问题,已修改
Q3: 数据查询存在问题??? 页面显示数据为t_user和t_role的交集
页面显示的用户信息和后台数据信息不一致;如admin1不显示在界面上
有设置角色的用户信息不显示
Q4:delete
删除表的信息时需要先删除表的关联外键,再删除
前端总结梳理
前端
1-先加载App.vue点击userList跳转到(router)跳转到
userList.vue界面
2-Template书写基本页面布局样式,按钮绑定等
3-script data() 中书写过程页面及交互所需要的数据和后端实体类有一定关联,一些state属性内容、数据校验规则
4-created()页面加载时运行
5-mthods增删查改方法
查询:
获取url:发送给后端的地址 config中配置三要素
param:发送给后端的数据参数,后端的数据输入
axios.post(url,param)
.then(response.data)对于后端反馈的数据进行处理
进行一些逻辑判断等
.catch()
.finally() 关闭窗口、更新数据等
技术点:AJAX,element-ui,Vue
后端梳理
后端
1-文件目录结构:三层架构:web层 service层 dao层
web层:
接受前端的数据并将其封装为实体类
创建业务层对象,调用业务层方法
将业务层返回对象转换为JSON返回给前端
service层(可使用接口配合BeanFactory使用)
实现业务层的CRUD方法,接受web层传递的数据
获取工厂类会话,运用动态代理实现接口方法
将数据库查询结果(实体类)返回给Web层
dao层
定义接口方法
单表CRUD使用注解开发
多表CRUD使用xml进行开发
pojo:
数据封装的实体类和数据库表、前端JSOPN强相关
po:存放数据库对应的实体类
vo:对应前后端交互Result、CRUD设计的实体类,方便数据流动
utils:
工具类:
BaseController:
接受前端的JSOPN数据并并解析为实体类
将Service层传递的实体类转换为前端可识别的JSON
EncodingFilter:解决前后端交互的request和response乱码问题
BeanFactory:获取业务层对象的工厂类(反射+读取配置文件+单例设计模式)
SqlSessionUtil:获取工厂会话类
XML开发:xml文件名需要和接口文件名一致+在统一文件路径下
配置文件类型:
beans.properties: BeanFactory实现对应的key和value(Service实现类的地址)
jdbc.properties:数据库参数的配置
mybatisConfig.xml:mybatis环境配置、相关的依赖包、Mapper映射
logback.xml:日志配置
2-针对不同角色进行CRUD开发
web层BaseServlet:使用反射进行所有CRUD方法的调用
集合pojo实体类搞清接受的类型和传入的参数
3-关于pojo中vo类的设计思路需要锻炼,一个好的设计,开发会非常顺畅
AddUser:数据库字段+角色List(一个用户对应多个角色)——根据数据库表之间的对应关系来实现
PageResult:作为返回给前端的数据 总记录数+List
QueryPageBean:前端查询数据封装的实体类
Result:返回给前端的实体类,所有类都可封装进该类进行数据传递
UpdateUser:前端需求字段(表字段)+List(一个User对应多个Role)
数据库表的实体类:表对应的字段+表之间的关系,如Role实体类中包含了
Set和Set两个集合
4-sql的CRUD实现 —— 单一表功能的CRUD需要考虑到对其他表的影响(外键约束)
单表的CRUD实现使用注解开发
多表CRUD中涉及中间表的修改,需要先将中间表进行修改(考虑外键约束)
如update User表时需修改User和Role表的中间表(先删除中间表信息再添加)
多表查询:
ResltMap
Type(接口方法的返回值类型)
配置user表和User实体类的主键映射关系
一个用户对应多个角色,使用标签collection
OfType为集合中保存的实体类型
propert表示User实体类集合中期对象名是roles
技术点:mybatis、mysql、反射、动态代理
部分Code
多表查询xml
<?xml version="1.0" encoding="UTF-8" ?>
insert into t_user_role values
(#{uid},#{rid})
updateUser表中的多表实现
public void updateUser(UpdateUser uu) {
SqlSession session = SqlSessionUtil.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
//1). 修改t_user表
mapper.updateUser(uu);
//2). 修改t_user_role表 : 先删除再添加
mapper.deleteRoleByUid(uu.getId());
//3). 向t_user_role表中添加用户和新角色的id
mapper.addRoleByUid(uu.getId(), uu.getRoleIds());
session.close();
}
工具类
会话工厂SqlSessionUtil
public class SqlSessionUtil {
private static SqlSessionFactory factory;
static {
//实例化工厂建造类
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//读取核心配置文件
try (InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml")) {
//创建工厂对象
factory = builder.build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
得到会话对象
@return 会话对象 : 自动提交事务
*/
public static SqlSession getSession() {
return factory.openSession(true);
}
/**
得到会话对象
@param isAutoCommit 是否自动提交事务
*/
public static SqlSession getSession(boolean isAutoCommit) {
return factory.openSession(isAutoCommit);
}
/*
* 提交事务并关闭session
* */
public static void commitAndClose(SqlSession session) {
if(session != null){
session.commit();
session.close();
}
}
/*
* 回滚事务并关闭session
* */
public static void rollbackAndClose(SqlSession session) {
if(session != null){
session.rollback();
session.close();
}
}
}
前后端数据交互请求响应
public class BaseController {
public static void printResult(HttpServletResponse response, Object obj) throws IOException {
response.setContentType("application/json;charset=utf8");// 设置返回类型
JSON.writeJSONString(response.getWriter(),obj);
}
public static T parseJSON2Object(HttpServletRequest request, Class tClass) throws IOException{
// 把json格式的表单数据直接转成T类型的对象
return JSON.parseObject(request.getInputStream(),tClass);
}
}
反射动态代理实现方法
public class BaseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取url路径携带的方法
String url = request.getRequestURI();
int index = url.lastIndexOf('/');
String methodName = url.substring(index+1);
//使用反射执行方法
//获取要执行的类的对象
Class<?> aClass = this.getClass();
try {
//使用class类调用要执行的方法
Method method = aClass.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//执行方法
method.invoke(this,request,response);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
处理请求响应乱码问题
@WebFilter("/*")
public class EncodingFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//解决请求乱码问题
request.setCharacterEncoding("utf-8");
//解决响应乱码问题
response.setContentType("text/html;charset=utf-8");
chain.doFilter(request, response);
}
}
生成业务层单例对象
public class BeansFactory {
//定义静态方法生成单例对象
private static HashMap map = new HashMap();
//创建静态方法生成单例对象
public static synchronized Object getSingleInstance(String beanName) throws Exception{
Object obj = map.get(beanName);
if(obj == null){
//读取保存实现类的配置文件
ResourceBundle bundle = ResourceBundle.getBundle("beans");
String userServiceStr = bundle.getString(beanName);
//使用反射根据上述读取的实现类全路径创建对象
Class clazz = Class.forName(userServiceStr);
//使用clazz实现UserServiceImp的无参构造
obj=clazz.newInstance();
//将创建的对象和key存储到map集合中
map.put(beanName,obj);
}
return obj;
}
}
小结
设计好代码的实现逻辑(UML)非常重要,想好再动手
出现bug时debug调试很关键、结合控制台输出信息+日志信息+google大法(stackoverflow)
学会查官方文档(element-ui)
学会使用浏览器抓包查看数据
浏览器查看源码及调试
从数据库表之间的关系入手,理清项目时自上而下,最后到具体业务
项目的文件结构很重要,清晰的结构可以使代码实现思路简单,且高内聚低耦合
数据表之间的多表查询需要考虑外键约束
完成一个功能就进行测试,避免后期代码bug过多
人生是不断遇到问题并解决问题的过程,程序工作中遇到的问题可能会更明显一点,你遇到的所有问题都有解决方案,不要急躁,一个个解决即可