欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SSH框架网上商城项目第24战之Struts2中处理多个Model请求的方法

程序员文章站 2024-03-12 09:25:44
1. 问题的提出   struts2中如果实现了modeldriven接口就可以将传来的参数注入到model中了,就可以在action中使用该m...

1. 问题的提出

  struts2中如果实现了modeldriven<model>接口就可以将传来的参数注入到model中了,就可以在action中使用该model,但是如果现在有两个model都需要在同一个action中使用该咋整呢?比如上一节我们完成了在线支付功能,但是支付完成了还没结束,我们需要接收从第三方那边反馈回来的信息,比如成功支付后,我们需要给付款方发送邮件和短信等。所以我们还需要在payaction中获取从第三方传过来的参数,由于从第三方传过来的参数与我们传过去的参数是不同的,所以接收那些参数我们也得写一个model(backdata),那么问题来了,我们的payaction已经写成这样子了:public class payaction extends baseaction<senddata>,即已经在baseaction中实现了modeldriven<senddata>接口了,那么如何在一个action中再接收一个model,并且还得对它们进行不同的处理呢?
  有种解决办法(其实也不能称为解决办法……因为根本就没解决……)就是写一个model,然后让senddata和backdata继承它,但是问题是这两个model根本就没关系,为啥要继承同一个model,所以这种解决办法实际上是在逃避上面的问题。
  在springmvc(springmvc还没真正开始学,如果有说错,请指正!)很好的解决了这个问题,因为springmvc中每个方法对应一个model,而不是每个action对应一个model,这就方便了,我在同一个action中写两个方法即可,不同的方法处理不同的model。

2. 问题的解决

  针对这个问题,struts2也提供了一种解决办法:
  struts2在actioncontext中存储了很多个map,比如之前提到的request, session, application等,其中还有个parametermap,该map中存储了request所有的请求参数,只要我们的action实现了parameteraware接口,就能拿到这个parametermap,这就跟modeldriven的道理是一样的,如果我们实现了modeldriven<model>接口,那么我们在action中就能获得该model,即定义一个model并实现set方法即可。
  好了,那现在问题好办了,支付的参数和返回的参数是不同的,也就是说两次进入payacition中的参数是不同的,即两次的parametermap中装的数据不一样,那只要我们在action中选取一个参数(该参数只要能区分两次是不同的request请求即可)作为判断,就知道当前该用哪个model来接收参数(senddata还是backdata)。下面我们改写一下payaction中的代码:

@controller("payaction")
@scope("prototype")
public class payaction extends baseaction<object> implements parameteraware {
//注意上面继承的baseaction中不能写senddata了,要写object,等下我们再判断具体使用哪个 

 //定义一个map接收request的请求参数
 private map<string, string[]> parameters;
 @override
 public void setparameters(map<string, string[]> parameters) {
  this.parameters = parameters;

 } 
 /*在struts-default.xml文中,servletconfig拦截器在modeldriven之前先执行,所以我们在注入model的时候,
 request参数已经有了,这样我们就可以在getmodel()方法中通过参数来判断是哪个请求了*/
 @override
 public object getmodel() {
 //付款的时候有支付通道编码的参数(pd_frpid),返回的时候没有
 //这样我们就可以通过该参数判断是支付还是返回了
  if(parameters.get("pd_frpid") != null) {
   model = new senddata();
  } else {
   model = new backdata();
  }
  return model;
 }

 //向易宝发送数据的方法
 public string gobank() {
  //对应发送的model:senddata
  senddata senddata = (senddata)model;
  //处理发送数据的逻辑,前一节已经实现过了……
 }

 //接收返回的数据的方法
 public void backbank() {
  //对应接收的model:backdata
  backdata backdata = (backdata)model;
  //处理返回数据的逻辑……后面再来实现,
  //先讲struts2处理多个model请求这个知识点
 }
}

3. struts2的处理流程

  我们再来分析一下struts2的执行流程,这样更加利于理解上面的原理。struts处理流程:

1)、获取请求后,先创建action的代理,在创建代理的时候顺便创建了action;
2)、执行18个拦截器,拦截器执行成功后再调用action的方法;
3)、action的方法执行完毕后,再调用18个拦截器
所以根据这个流程,我们知道:先创建action–>再执行拦截器(先执行servletconfig,再执行modeldriven,因为servletconfig拦截器配在modeldriven的前面)。所以在上面的代码中,我们才可以在getmodel()方法中去拿parametermap中的数据来进行判断。  
  用下面简单的时序图来直观的表示一下上面的处理流程吧:

SSH框架网上商城项目第24战之Struts2中处理多个Model请求的方法

这就很直观的看出struts2的处理流程了,那么对于上面处理多个model请求也很好理解了。到这里,struts2处理多个model请求的方法部分已经分析完了,下面针对本项目中的一个小逻辑,做一下完善。

4. 完善接收数据的方法

  上面遗留了一个逻辑的实现,即处理返回的数据,这里的逻辑主要有:更新订单状态(已付款,已发货等),发送邮件,发送短信等。我们先把更新订单状态完成,主语发送邮件和发送短信的功能,我们后面再写。
先完善backbank()方法:

public void backbank() {
 backdata backdata = (backdata)model;
 system.out.println(model);
 boolean isok = payservice.checkbackdata(backdata);
 if(isok) {
  //1. 更新订单状态,参数是自己根据数据库中的情况传进去的,用来测试
  forderservice.updatestatusbyid(integer.valueof(201605006), 2);
  //2. 根据user邮箱地址,发送邮件
  //3. 发送手机短信
  system.out.println("----success!!----");
 } else {
  system.out.println("----false!!!----");
 }
}

然后我们完成payservice中的checkbackdata(backdata)方法(逻辑和21节中的基本一样):

@service("payservice")
public class payserviceimpl implements payservice {
  //省略不相关代码
  /******************************上面是发送请求的方法**************************************/
  // 完成返回数据的追加
  private string joinbackdataparam(backdata backdata) {
   // 追加字符串,为加密验证做准备
   stringbuffer infobuffer = new stringbuffer();
   infobuffer.append(backdata.getp1_merid());
   infobuffer.append(backdata.getr0_cmd());
   infobuffer.append(backdata.getr1_code());
   infobuffer.append(backdata.getr2_trxid());
   infobuffer.append(backdata.getr3_amt());
   infobuffer.append(backdata.getr4_cur());
   infobuffer.append(backdata.getr5_pid());
   infobuffer.append(backdata.getr6_order());
   infobuffer.append(backdata.getr7_uid());
   infobuffer.append(backdata.getr8_mp());
   infobuffer.append(backdata.getr9_btype());
   return infobuffer.tostring();
  }

  // 对返回来的数据进行加密,并且和传过来的密文进行比较,如果ok则说明数据没有被篡改
  public boolean checkbackdata(backdata backdata){
   string joinparam=this.joinbackdataparam(backdata);
   // 加密后得到自己的密文
   string md5 = digestutil.hmacsign(joinparam.tostring(),key);
   // 密文和传过来密文比较
   return md5.equals(backdata.gethmac());
  } 
}

最后我们完成forderservice中的updatestatusbyid方法:

//forderservice接口
public interface forderservice extends baseservice<forder> {
 //省略其他无关代码……
 //根据订单编号,更新订单状态
 public void updatestatusbyid(int id, int sid);
}

//forderserviceimpl实现类
@service("forderservice")
public class forderserviceimpl extends baseserviceimpl<forder> implements forderservice {

 //省略其他无关代码

 @override
 public void updatestatusbyid(int id, int sid) {
  string hql = "update forder f set f.status.id=:sid where f.id=:id";
  getsession().createquery(hql)
   .setinteger("sid", sid)
   .setinteger("id", id)
   .executeupdate();
 } 
}

  这样就能在顾客付款后更新订单状态了。

原文链接:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。