前后端参数传递方式演化史
写服务端比较头疼的事情就是从前端往后台传递参数了,一般的套路是:
前端页面写一大堆乱七八糟的参数 --> 传递到后台 --> 后台接收并且提取封装为一个对象,然后拿这个对象去进行各种业务操作。
v0.1 最早的时候是使用的Servlet,它是这样子的:
前端代码:
<form action="loginServlet" method="post"> 用户名:<input type="text" name="username" /><br/> 密 码:<input type="password" name="passwd" /><br/> <input type="submit" value="登录" /> </form>
接收参数的Servlet代码:
1 @WebServlet(urlPatterns={"/loginServlet"}) 2 public class LoginServlet extends HttpServlet { 3 4 @Override 5 protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { 6 process(req,resp); 7 } 8 9 @Override 10 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException ,IOException { 11 process(req,resp); 12 } 13 14 private void process(HttpServletRequest req, HttpServletResponse resp) throws ServletException ,IOException{ 15 String username=req.getParameter("username"); 16 String passwd=req.getParameter("passwd"); 17 18 User u=new User(); 19 u.setUsername(username); 20 u.setPasswd(passwd); 21 22 //blabla.... 23 24 } 25 26 }
这种方式需要我们手动的一个个把参数扣出来然后打包成对象。
v0.2 后来有了struts2,它有一个参数拦截器可以自动地将参数拍进去:
前端页面:
<form action="loginAction" method="post"> 用户名:<input type="text" name="username" /><br/> 密 码:<input type="password" name="passwd" /><br/> <input type="submit" value="登录" /> </form>
Action代码:
1 public class LoginAction extends ActionSupport { 2 3 private String username; 4 private String passwd; 5 6 public String login(){ 7 8 User u=new User(); 9 u.setUsername(username); 10 u.setPasswd(passwd); 11 12 //do something... 13 14 return SUCCESS; 15 } 16 17 public String getUsername() { 18 return username; 19 } 20 21 public void setUsername(String username) { 22 this.username = username; 23 } 24 25 public String getPasswd() { 26 return passwd; 27 } 28 29 public void setPasswd(String passwd) { 30 this.passwd = passwd; 31 } 32 33 }
这个时候可以在login()中直接使用username和passwd,因为参数拦截器已经把它们的值拍进去了,但是仍然需要我们手动的把参数组合成对象。
v0.3 既然都已经可以拍进去,为什么不干脆彻底一点呢?
前端代码:
<form action="loginAction" method="post"> 用户名:<input type="text" name="user.username" /><br/> 密 码:<input type="password" name="user.passwd" /><br/> <input type="submit" value="登录" /> </form>
Action代码:
1 public class LoginAction extends ActionSupport { 2 3 private User user=new User(); 4 5 public String login() { 6 7 System.out.println(user.getUsername()+","+user.getPasswd()); 8 9 return SUCCESS; 10 } 11 12 public User getUser() { 13 return user; 14 } 15 16 public void setUser(User user) { 17 this.user = user; 18 } 19 20 }
但是这样子的话在前端页面写的时候还是多了一级导航,还能更好吗?
v0.4 原来还有更酷更优雅的办法呢~ ModelDriven
前端代码:
<form action="loginAction" method="post"> 用户名:<input type="text" name="username" /><br/> 密 码:<input type="password" name="passwd" /><br/> <input type="submit" value="登录" /> </form>
后台代码:
1 public class LoginAction extends ActionSupport implements ModelDriven { 2 3 private User user; 4 5 public String login() { 6 7 System.out.println(user.getUsername()+","+user.getPasswd()); 8 9 return SUCCESS; 10 } 11 12 public User getUser() { 13 return user; 14 } 15 16 public void setUser(User user) { 17 this.user = user; 18 } 19 20 @Override 21 public Object getModel() { 22 if(user==null) user=new User(); 23 return user; 24 } 25 26 }
啊哈返璞归真了,从v0.2开始依赖的就是struts2的参数拦截器把参数拍进来,而最后一个v0.4依赖的则是ModelDriven拦截器将对象设置到ValueStack的栈顶,因为ValueStack有暴露栈中对象属性可直接使用属性名访问的特性,所以在前台可以直接使用username和passwd传递参数。
总结:
通过四个版本可以看出参数传递的发展趋势,(v0.1)最开始的时候我们是一个属性一个属性的往后面传,然后到了后面手动的扣出来组合成对象,后面发展了一下,既然都过来了为什么还要手动的扣呢?不如你直接给我拍进来吧,参数拦截器应运而生(v0.2),再后来发现参数拦截器也只是省去了request.getParameter()这种步骤,但是还是要我们自己手动组合成对象啊,这样不好,于是就想干脆拍进来之后就是对象吧,于是就持有一个对象类型的成员属性,然后拍进来之后直接就是对象了(v0.3),但是这样还有有一个弊端啊,在前端页面上传递的时候写名字要深入一层,好麻烦的啊,于是ModelDriven应运而生,这个东西在传递参数的时候把成员属性对象放到值栈的栈顶,借助其暴露栈中对象属性的特性就可以在前端直接访问成员属性对象的属性了(v0.4)。
参数拦截器:(待修改网址引用)
ModelDriven拦截器:(待修改网址引用)
.