生成订单的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项目添加权限控制.....
只有用户有权限的时候,后台管理才可以进行相对应的操作.....
实现思路
之前我们做权限管理系统的时候,是根据用户请求的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了。
- 在数据库中添加了两个权限
为id为1的user添加了两个权限
编写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上得到异常,再给出友好的提示。。
效果:
- 没有登陆的时候:
- 登陆了,但是没有相对应的权限的时候
- 登陆了,并且有权限
要点总结
该权限控制是十分优雅的,只要我在Service层中添加一个注解...那么当web层调用该方法的时候就需要判断用户有没有该权限....
- 外界调用Service层的方法是代理调用invoke()方法,我们在invoke()方法可以对其进行增强!
- invoke()方法内部就是在查询调用该方法上有没有注解,如果没有注解,就可以直接调用。如果有注解,那么就得到注解的信息,判断该用户有没有权限来访问这个方法
- 在反射具体方法的时候,必须记得要给出相对应的参数!
- 在invoke()方法抛出的编译时期异常,java会自动转换成运行期异常进行抛出...
- 使用contains()方法时,就要重写该对象的hashCode()和equals()