使用基於servlet的攔截器實現訂單提交控制Demo
阿新 • • 發佈:2019-01-26
首先提交訂單前需要進行庫存校驗等一系列的準備操作流程,故可以在提交訂單流程的基礎上進行攔截器的預提交操作。
具體Demo如下:
首先編輯攔截器:
package com.sanbang.interceptors; import org.apache.log4j.Logger; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class putOrderFromsInterceptor implements HandlerInterceptor { private static Logger log = Logger.getLogger(putOrderFromsInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //在此可以新增庫存校驗等預提交程式碼的部分 System.out.println("putOrderFromsInterceptor-----------preHandle" ); log.info("putOrderFromsInterceptor-----------preHandle"); response.sendRedirect("/front/app/goods/trytest.htm?mess='jhgjh'"); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("putOrderFromsInterceptor-----------postHandle" ); log.info("putOrderFromsInterceptor-----------postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("putOrderFromsInterceptor-----------afterCompletion" ); log.info("putOrderFromsInterceptor-----------afterCompletion"); } }
配置攔截器:
<mvc:interceptors> <!--下單攔截 校驗--> <mvc:interceptor> <!--下單介面的URL--> <mvc:mapping path="/app/goods/dealImmediatelyBuyGood.htm"/> <bean class="com.sanbang.interceptors.putOrderFromsInterceptor" /> </mvc:interceptor> </mvc:interceptors>
具體下單操作方法如下:
@RequestMapping(value = "/dealImmediatelyBuyGood") @ResponseBody @Transactional(rollbackFor=Exception.class,propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,timeout=5000) public synchronized Object dealImmediatelyBuyGood(HttpServletRequest request, HttpServletResponse response, Long WeAddressId, Long goodsId, Double count) { Map<String, Object> mmp = null; Result rs = Result.failure(); try { ezs_user user = RedisUserSession.getUserInfoByKeyForApp(request); if (user == null) { rs = Result.failure(); rs.setErrorcode(DictionaryCode.ERROR_WEB_SESSION_ERROR); rs.setMsg("使用者未登入"); return rs; } else { Long auditingusertype_id = user.getEzs_store().getAuditingusertype_id(); ezs_dict dictCode = dictService.getDictByThisId(auditingusertype_id); if (dictCode.getSequence() <= 3) { if (user.getEzs_store().getStatus() != 2) { rs = Result.failure(); rs.setErrorcode(DictionaryCode.ERROR_WEB_PARAM_ERROR); rs.setMsg("您還未完成實名認證,請去個人中心完成實名認證!"); return rs; } } } ezs_orderform orderForm = new ezs_orderform(); ezs_goods buyGoods = null; // 修改訂單號生成規則 try{ buyGoods = this.ezs_goodsMapper.selectByPrimaryKey(goodsId); orderForm.setOrder_no(createOrderNo(buyGoods)); }catch(Exception e){ e.printStackTrace(); log.info("訂單號生成失敗"); } boolean isour=this.childCompanyGoodsService.isChildCompanyGood(buyGoods); if(isour){ mmp = this.childCompanyGoodsService.immediateAddOrderFormFunc(orderForm, user, "GOODS", WeAddressId, buyGoods, count); }else{ mmp = this.goodsService.immediateAddOrderFormFunc(orderForm, user, "GOODS", WeAddressId, buyGoods, count); } Integer ErrorCode = (Integer) mmp.get("ErrorCode"); if (ErrorCode != null && ErrorCode.equals(DictionaryCode.ERROR_WEB_REQ_SUCCESS)) { rs = Result.success(); rs.setMsg(mmp.get("Msg").toString()); } else { rs = Result.failure(); rs.setMsg(mmp.get("Msg").toString()); } //判斷是否為子公司 /*if(isour&&rs.getSuccess()) { rs=CheckOrderService.signContentProcess(rs, orderForm.getOrder_no()); if(!rs.getSuccess()) { throw new Exception("立即下單:簽章錯誤orderno="+orderForm.getOrder_no()+"錯誤資訊為:"+rs.toString()); } }*/ } catch (Exception e) { e.printStackTrace(); rs.setSuccess(false); rs.setMsg("提交訂單失敗"); } return rs; }
如此即可實現對下單的攔截。
亦可使用基於AOP的方式實現下單操作前校驗,如下:基於註解的aspect
首先是execution()函式 用來匹配執行方法的連線點
語法結構: execution( 方法修飾符 方法返回值 方法所屬類 匹配方法名 ( 方法中的形參表 ) 方法申明丟擲的異常 )
其中(方法返回值、匹配方法名 ( 方法中的形參表 ))不能省略的,各部分都支援萬用字元 “*” 來匹配全部。
比較特殊的為形參表部分,其支援兩種萬用字元
- "*":代表一個任意型別的引數;
- “..”:代表零個或多個任意型別的引數。
例如:
()匹配一個無參方法
(..)匹配一個可接受任意數量引數和型別的方法
(*)匹配一個接受一個任意型別引數的方法
(*,Integer)匹配一個接受兩個引數的方法,第一個可以為任意型別,第二個必須為Integer。
程式碼例項如下:
首先新增啟用aop配置:
<aop:aspectj-autoproxy proxy-target-class="true" />
package com.sanbang.Aspects;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Aspect
@Component
public class putOrderFormAspect {
private static Logger log = Logger.getLogger(putOrderFormAspect.class);
/**
* 定義一個方法,用於宣告切入點表示式,方法中一般不需要新增其他程式碼
* 使用@Pointcut宣告切入點表示式
* 後面的通知直接使用方法名來引用當前的切點表示式;如果是其他類使用,加上包名即可
*/
@Pointcut("execution(public * com.sanbang.app.controller.AppGoodsController.dealImmediatelyBuyGood(..))")
public void declearJoinPointExpression(){}
/**
* 前置通知
* @param joinPoint
*/
@Before("declearJoinPointExpression()") //該標籤宣告次方法是一個前置通知:在目標方法開始之前執行
public void beforMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
//獲取目標方法的傳入引數,可按照索引進行獲取
for (int i=0;i<args.length;i++){
System.out.println("引數"+i+":"+args[i].toString());
}
System.out.println("this method "+methodName+" begin. param<"+ args+">");
log.info("beforMethod 開始執行。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。");
}
/**
* 後置通知(無論方法是否發生異常都會執行,所以訪問不到方法的返回值)
* @param joinPoint
*/
@After("declearJoinPointExpression()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("this method "+methodName+" end.");
}
/**
* 返回通知(在方法正常結束執行的程式碼)
* 返回通知可以訪問到方法的返回值!
* @param joinPoint
*/
@AfterReturning(value="declearJoinPointExpression()",returning="result")
public void afterReturnMethod(JoinPoint joinPoint,Object result){
String methodName = joinPoint.getSignature().getName();
System.out.println("this method "+methodName+" end.result<"+result+">");
}
/**
* 異常通知(方法發生異常執行的程式碼)
* 可以訪問到異常物件;且可以指定在出現特定異常時執行的程式碼
* @param joinPoint
* @param ex
*/
@AfterThrowing(value="declearJoinPointExpression()",throwing="ex")
public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println("this method "+methodName+" end.ex message<"+ex+">");
}
/**
* 環繞通知(需要攜帶型別為ProceedingJoinPoint型別的引數)
* 環繞通知包含前置、後置、返回、異常通知;ProceedingJoinPoin 型別的引數可以決定是否執行目標方法
* 且環繞通知必須有返回值,返回值即目標方法的返回值
* @param point
*/
@Around(value="declearJoinPointExpression()")
public Object aroundMethod(ProceedingJoinPoint point){
Object result = null;
String methodName = point.getSignature().getName();
try {
//前置通知
System.out.println("The method "+ methodName+" start. param<"+ Arrays.asList(point.getArgs())+">");
//執行目標方法
result = point.proceed();
//返回通知
System.out.println("The method "+ methodName+" end. result<"+ result+">");
} catch (Throwable e) {
//異常通知
System.out.println("this method "+methodName+" end.ex message<"+e+">");
throw new RuntimeException(e);
}
//後置通知
System.out.println("The method "+ methodName+" end.");
return result;
}
}