图书管理系统【用户、购买、订单模块、添加权限】(三)

简介: 笔记

生成订单的Servlet


BussinessServiceImplservice=newBussinessServiceImpl();


       //检查该用户的购物车是否有商品

       Cartcart=(Cart)request.getSession().getAttribute("cart");

       if(cart==null){

           request.setAttribute("message","您购物车没有商品,无法生成订单");

           request.getRequestDispatcher("/message.jsp").forward(request,response);

           return;

       }


       //如果有商品,得到当前用户

       Useruser=(User)request.getSession().getAttribute("user");

       service.createOrder(cart,user);

       request.setAttribute("message","订单已经生成了,准备好钱来收货把");

       request.getRequestDispatcher("/message.jsp").forward(request,response);

       return;


用户查询自己的订单Servlet


<ahref="${pageContext.request.contextPath}/LookOrder"target="body">查看订单</a>

BussinessServiceImplservice=newBussinessServiceImpl();


       //检查该用户是否登陆了

       Useruser=(User)request.getSession().getAttribute("user");

       if(user==null){

           request.setAttribute("message","您还没登陆,等您登陆了再来看把");

           request.getRequestDispatcher("/message.jsp").forward(request,response);

           return;

       }


       //用户登陆了!

       Orderorder=service.findUserOrder(user.getId());


       //交给相对应的JSP 显示

       request.setAttribute("order",order);

       request.setAttribute("user",user);

       request.getRequestDispatcher("/client/listOrder.jsp").forward(request,response);

       return;


显示订单数据的JSP


<c:iftest="${order==null}">

   您还没有下过任何订单!!


</c:if>


<c:iftest="${order!=null}">


   <tableborder="1px">


       <tr>

           <td>下单人:</td>

           <td>订单时间</td>

           <td>订单状态</td>

           <td>订单价钱</td>

       </tr>

       <tr>

           <td>${user.username}</td>

           <td>${order.ordertime}</td>

           <td>${order.state==false?"未发货":"已发货"}</td>

           <td>${order.price}</td>

       </tr>


   </table>


</c:if>



后台查询订单的状况Servlet


<ahref="${pageContext.request.contextPath}/OrderServlet?state=false"target="body">待处理订单</a><br>

<ahref="${pageContext.request.contextPath}/OrderServlet?state=true"target="body">已发货订单</a><br>

BussinessServiceImplservice=newBussinessServiceImpl();

       Stringstate=request.getParameter("state");


       if(state.equals("true")){

           List<Order>list=service.getAllOrder(true);

           request.setAttribute("list",list);


       }elseif(state.equals("false")){

           List<Order>list=service.getAllOrder(false);

           request.setAttribute("list",list);

       }



       request.getRequestDispatcher("/background/listOrder.jsp").forward(request,response);


显示订单状况的JSP


<c:iftest="${empty(list)}">


   还没有任何订单哦!


</c:if>


<c:iftest="${!empty(list)}">


   <tableborder="1px">


       <tr>

           <td>下单人:</td>

           <td>订单时间</td>

           <td>订单状态</td>

           <td>订单价钱</td>

           <td>操作</td>

       </tr>


       <c:forEachitems="${list}"var="order">

           <tr>

               <td>${order.user_id}</td>

               <td>${order.ordertime}</td>

               <td>${order.state==false?"未发货":"已发货"}</td>

               <td>${order.price}</td>

               <td>

                   <ahref="${pageContext.request.contextPath}/orderItemServlet?order_id=${order.id}">查看详细信息</a>

                   <ahref="#">删除</a>


               </td>

           </tr>

       </c:forEach>



   </table>



</c:if>


查看具体订单的详细信息Servlet


BussinessServiceImplservice=newBussinessServiceImpl();


       //得到用户想要查看详细信息的表单

       Stringorder_id=request.getParameter("order_id");


       Orderorder=service.findOrder(order_id);


       //将该order对象给相对应的JSP显示

       request.setAttribute("order",order);

       request.getRequestDispatcher("/background/listDetail.jsp").forward(request,response);


查看具体订单的详细信息JSP


<tableborder="1px">


  <tr>

      <td>书籍的编号</td>

      <td>价钱</td>

      <td>数量</td>

      <td>操作</td>

  </tr>

   <c:forEachitems="${order.items}"var="item">

       <tr>

           <td>${item.book_id}</td>

           <td>${item.price}</td>

           <td>${item.quantity}</td>

           <td><ahref="${pageContext.request.contextPath}/SendOutServlet?id=${order.id}">发货</a></td>

       </tr>

   </c:forEach>

</table>


处理发货的Servlet


BussinessServiceImplservice=newBussinessServiceImpl();

       Stringid=request.getParameter("id");


       service.sendOutOrder(id);

       request.setAttribute("message","已发货!");

       request.getRequestDispatcher("/message.jsp").forward(request,response);

       return;



添加权限控制


目前为止,我们已经学习了动态代理技术和注解技术了。于是我们想要为之前的bookStore项目添加权限控制.....

只有用户有权限的时候,后台管理才可以进行相对应的操作.....


实现思路

46.jpg

之前我们做权限管理系统的时候,是根据用户请求的URI来判断该链接是否需要权限的。这次我们使用动态代理的技术和注解来判断:用户调用该方法时,检查该方法是否需要权限...

根据MVC模式,我们在web层都是调用service层来实现功能的。那么我们具体的思路是这样的:

  • web层调用service层的时候,得到的并不是ServiceDao对象,而是我们的代理对象
  • 在service层中的方法添加注解,如果方法上有注解,那么说明调用该方法需要权限...
  • 当web层调用代理对象方法的时候,代理对象会判断该方法是否需要权限,再给出相对应的提示....


设计实体、数据库表


上次我们做的权限管理系统是引入了角色这个概念的,这次主要为了练习动态代理和注解技术,就以简单为主,不引入角色这个实体。直接是用户和权限之间的关系了。


Privilege实体


publicclassPrivilege{


   privateStringid;

   privateStringname;


   publicStringgetId(){

       returnid;

   }


   publicvoidsetId(Stringid){

       this.id=id;

   }


   publicStringgetName(){

       returnname;

   }


   publicvoidsetName(Stringname){

       this.name=name;

   }

}


数据库表


  • privilege表

CREATETABLEprivilege(


 id   VARCHAR(40)PRIMARYKEY,

 nameVARCHAR(40)


);

privilege和user是多对多的关系,于是使用第三方表来维护他们的关系

  • user_privilege表

CREATETABLEuser_privilege(

 privilege_idVARCHAR(40),

 user_id      VARCHAR(40),


 PRIMARYKEY(privilege_id,user_id),

 CONSTRAINTprivilege_id_FKFOREIGNKEY(privilege_id)REFERENCESprivilege(id),

 CONSTRAINTuser_id_FK1FOREIGNKEY(user_id)REFERENCESuser(id)


);



添加测试数据


为了方便,直接添加数据了。就不写详细的DAO了。

  • 在数据库中添加了两个权限

48.jpg

为id为1的user添加了两个权限

49.jpg


编写DAO


后面在动态代理中,我们需要检查该用户是否有权限...那么就必须查找出该用户拥有的哪些权限。再看看用户有没有相对应的权限

//查找用户的所有权限

   publicList<Privilege>findUserPrivilege(Stringuser_id){

       QueryRunnerqueryRunner=newQueryRunner(Utils2DB.getDataSource());


       Stringsql="SELECT p.* FROM privilege p, user_privilege up WHERE p.id = up.privilege_id AND up.user_id = ?";

       try{

           return(List<Privilege>)queryRunner.query(sql,newObject[]{user_id},newBeanListHandler(Privilege.class));

       }catch(SQLExceptione){

           thrownewRuntimeException(e);

       }

   }


抽取到接口上


List<Privilege>findUserPrivilege(Stringuser_id);



注解模块


  • 编写注解

@Retention(RetentionPolicy.RUNTIME)

public@interfacepermission{

   Stringvalue();

}

  • 在Service层方法中需要权限的地方添加注解CategoryServiceImpl

@permission("添加分类")

   /*添加分类*/

   publicvoidaddCategory(Categorycategory){

       categoryDao.addCategory(category);

   }



   /*查找分类*/

   publicvoidfindCategory(Stringid){

       categoryDao.findCategory(id);

   }


   @permission("查找分类")

   /*查看分类*/

   publicList<Category>getAllCategory(){

       returncategoryDao.getAllCategory();

   }


抽取Service


把Service的方法抽取成ServiceDao。在Servlet中,也是通过ServiceFactory来得到Service的对象【和DaoFactory是类似的】


CategoryService


@permission("添加分类")

   /*添加分类*/voidaddCategory(Categorycategory);


   /*查找分类*/

   voidfindCategory(Stringid);


   @permission("查找分类")

   /*查看分类*/List<Category>getAllCategory();


ServiceFactory


publicclassServiceDaoFactory{


   privatestaticfinalServiceDaoFactoryfactory=newServiceDaoFactory();


   privateServiceDaoFactory(){

   }


   publicstaticServiceDaoFactorygetInstance(){

       returnfactory;

   }



   //需要判断该用户是否有权限

   public<T>TcreateDao(StringclassName,Class<T>clazz,finalUseruser){


       System.out.println("添加分类进来了!");


       try{

           //得到该类的类型

           finalTt=(T)Class.forName(className).newInstance();

           //返回一个动态代理对象出去

           return(T)Proxy.newProxyInstance(ServiceDaoFactory.class.getClassLoader(),t.getClass().getInterfaces(),newInvocationHandler(){


               @Override

               publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsNoSuchMethodException,InvocationTargetException,IllegalAccessException,PrivilegeException{

                   //判断用户调用的是什么方法

                   StringmethodName=method.getName();

                   System.out.println(methodName);


                   //得到用户调用的真实方法,注意参数!!!

                   Methodmethod1=t.getClass().getMethod(methodName,method.getParameterTypes());


                   //查看方法上有没有注解

                   permissionpermis=method1.getAnnotation(permission.class);


                   //如果注解为空,那么表示该方法并不需要权限,直接调用方法即可

                   if(permis==null){

                       returnmethod.invoke(t,args);

                   }


                   //如果注解不为空,得到注解上的权限

                   Stringprivilege=permis.value();


                   //设置权限【后面通过它来判断用户的权限有没有自己】

                   Privilegep=newPrivilege();

                   p.setName(privilege);


                   //到这里的时候,已经是需要权限了,那么判断用户是否登陆了

                   if(user==null){


                       //这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。

                       thrownewPrivilegeException("对不起请先登陆");

                   }


                   //执行到这里用户已经登陆了,判断用户有没有权限

                   Methodm=t.getClass().getMethod("findUserPrivilege",String.class);

                   List<Privilege>list=(List<Privilege>)m.invoke(t,user.getId());


                   //看下权限集合中有没有包含方法需要的权限。使用contains方法,在Privilege对象中需要重写hashCode和equals()

                   if(!list.contains(p)){

                       //这里抛出的异常是代理对象抛出的,sun公司会自动转换成运行期异常抛出,于是在Servlet上我们根据getCause()来判断是不是该异常,从而做出相对应的提示。

                       thrownewPrivilegeException("您没有权限,请联系管理员!");

                   }


                   //执行到这里的时候,已经有权限了,所以可以放行了

                   returnmethod.invoke(t,args);

               }

           });


       }catch(Exceptione){

           newRuntimeException(e);

       }

       returnnull;

   }

}


PrivilegeExcetption


当用户没有登陆或者没有权限的时候,我们应该给用户一些友好的提示....于是我们自定义了PrivilegeException

publicclassPrivilegeExceptionextendsException{


   publicPrivilegeException(){

       super();

   }


   publicPrivilegeException(Stringmessage){

       super(message);

   }


   publicPrivilegeException(Stringmessage,Throwablecause){

       super(message,cause);

   }


   publicPrivilegeException(Throwablecause){

       super(cause);

   }

}

我们继承的是Exception,通过方法名抛出去。但是我们是通过代理对象调用方法的,于是sun公司的策略就是把它们转换成运行期异常抛出去

因此,我们就在Servlet上得到异常,再给出友好的提示。。


效果:


  • 没有登陆的时候:

49.gif

  • 登陆了,但是没有相对应的权限的时候
  • 登陆了,并且有权限

50.gif


要点总结


该权限控制是十分优雅的,只要我在Service层中添加一个注解...那么当web层调用该方法的时候就需要判断用户有没有该权限....

  1. 外界调用Service层的方法是代理调用invoke()方法,我们在invoke()方法可以对其进行增强!
  2. invoke()方法内部就是在查询调用该方法上有没有注解,如果没有注解,就可以直接调用。如果有注解,那么就得到注解的信息,判断该用户有没有权限来访问这个方法
  3. 在反射具体方法的时候,必须记得要给出相对应的参数!
  4. 在invoke()方法抛出的编译时期异常,java会自动转换成运行期异常进行抛出...
  5. 使用contains()方法时,就要重写该对象的hashCode()和equals()


目录
相关文章
|
9月前
|
弹性计算 Linux 网络安全
基于阿里云ECS+Cloudreve搭建私人网盘系统
本文介绍了阿里云ECS服务器的测评及最佳实践。
306 4
基于阿里云ECS+Cloudreve搭建私人网盘系统
|
3月前
|
监控 安全 网络安全
Windows Server管理:配置与管理技巧
Windows Server管理:配置与管理技巧
140 3
|
3月前
|
Java
如何在 Java 中处理“Broken Pipe”异常
在Java中处理“Broken Pipe”异常,通常发生在网络通信中,如Socket编程时。该异常表示写入操作的另一端已关闭连接。解决方法包括:检查网络连接、设置超时、使用try-catch捕获异常并进行重试或关闭资源。
176 5
|
7月前
|
分布式计算 DataWorks Oracle
MaxCompute产品使用合集之如何创建表
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
151 7
|
7月前
|
存储 运维 安全
问题记录:解决Linux登录故障,/etc/passwd配置受损该怎么操作
在维护Linux系统的过程中,可能会遇到各种紧急情况,其中/etc/passwd文件的损坏是运维人员特别需要准备应对的一种情形。该文件作为Linux用户账户信息的核心存储,一旦遭到破坏,会直接导致用户无法登录,甚至系统服务失败。这次处理问题的记录会提供一个详细步骤,以帮助恢复损坏的/etc/passwd文件,从而快速解决登录失败危机。
问题记录:解决Linux登录故障,/etc/passwd配置受损该怎么操作
|
6月前
|
负载均衡 应用服务中间件 Linux
"揭晓nginx的神秘力量:如何实现反向代理与负载均衡,拯救服务器于水火?"
【8月更文挑战第20天】在Linux环境下,nginx作为高性能HTTP服务器与反向代理工具,在网站优化及服务器负载均衡中扮演重要角色。本文通过电商平台案例,解析nginx如何解决服务器压力大、访问慢的问题。首先介绍反向代理原理,即客户端请求经由代理服务器转发至内部服务器,隐藏真实服务器地址;并给出配置示例。接着讲解负载均衡原理,通过将请求分发到多个服务器来分散负载,同样附有配置实例。实践表明,采用nginx后,不仅服务器压力得到缓解,还提升了访问速度与系统稳定性。
176 3
|
XML Java 数据库连接
使用 MyBatis 的 Maven 插件生成代码
使用 MyBatis 的 Maven 插件生成代码
 使用 MyBatis 的 Maven 插件生成代码
|
自然语言处理 Java API
阿里云自然语言处理--智能文本分类(基础版-新闻领域)Quick Start
自然语言处理(Natural Language Processing,简称NLP),是为各类企业及开发者提供的用于文本分析及挖掘的核心工具,旨在帮助用户高效的处理文本,已经广泛应用在电商、文娱、司法、公安、金融、医疗、电力等行业客户的多项业务中,取得了良好的效果。智能文本分类可将用户输入的一段文本自动映射到具体的类目上,帮助用户快速完成文本的分类,并针对文本中的关键标签进行识别和提取。支持平层类目体系或者以树状形式组织的层次类目体系,当前系统内置两种默认分类体系可直接使用:新闻资讯领域内类类目体系、电商领域类目体系。本文将使用Java CommonSDK演示智能文本分类服务的快速调用以供参考。
763 0
阿里云自然语言处理--智能文本分类(基础版-新闻领域)Quick Start
|
存储 Kubernetes API
Argo CD 【2】动手实践
Argo CD 【2】动手实践
Argo CD 【2】动手实践

热门文章

最新文章