你还在使用getParameter吗?使用反射自定义一个简易的类似与Spring MVC的参数自动映射

    科技2022-07-10  112

    SpringMVC页面向controller层传值的自动映射条件,

    表单的name值与参数名对应,或使用注解@RequestParam进行对象,或与对象中的属性名对应,并且需要提供setter方法,才能完成参数的赋值,其中是如何进行赋值的过程我们并不知道吗、,也不关心,只知道、如何去使用它就够了,这也就是我们学习效率不高的原因,只知其然,不知其所以然

    下面是模拟springMVC向入参为对象中映射值的过程,从此不在Servlet中使用request.getParameter;

    条件:

    表单name属性的值必须与对象属性名相同必须提供属性公共的setter方法

    在学习的过程中我们要常保持疑问,带着问题去学习,如果你连疑问都没有,那你自然就不知道你想要的答案是什么,没有想要的答案,也就没有学习的价值,先声明你的疑问,再去学习, 疑问:就是为什么需要这两个条件成立

    准备代码:一个实体类,一个表单,一个servlet,

    package com.entity; import java.util.Date; /** *实体类,将参数值保存在此对象中 */ public class Student { private String name; private Integer age; private Double score; private Date birthDay; public Date getBirthDay() { return birthDay; } public void setBirthDay(Date birthDay) { this.birthDay = birthDay; } public Student() { System.out.println("Student的无参构造"); } public String getName() { return name; } public void setName(String name) { this.name = name; System.out.println("setName--------》"); } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Double getScore() { return score; } public void setScore(Double score) { this.score = score; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", score=" + score + ", birthDay=" + birthDay + '}'; } }

    表单 ,注:此处使用的是jsp,name值都与实体类中的属性名对应

    <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <body> <form action="studentServlet" method="post"> name: <input type="text" name="name"><br> age:<input type="text" name="age"><br> score:<input type="text" name="score"><br> birthDay: <input type="text" name="birthDay"><br> <input type="submit" value="提交"><br> </form> </body> </html>

    在参数自动映射中,我们也只能在Servlet中进行做文章了,为了代码的重用性,我将参数自动映射功能,封装成一个方法,想要使用只需要将此类拷贝即可,方法的具体内容:

    package com.utils; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Enumeration; public class BeanOperateTools { /** * 该方法是由Servlet调用 * 具体实现的参数封装方法 * @param obj 要将表单值封装至的对象 * @param req request对象,包含我们表单请求来的数据 * @throws Exception 可能抛出的异常 */ public static void setValueSimple(Object obj, HttpServletRequest req) throws Exception { //得到实体类的类信息 Class<?> cls = obj.getClass(); //获取所有的参数名称 Enumeration<String> enu = req.getParameterNames(); //遍历参数名称 while (enu.hasMoreElements()){ //获取参数名称 String paramName = enu.nextElement(); //获取对应的参数名称的值 String paramValue = req.getParameter(paramName); //进行判断当前文本框是否填写值,没有值就跳过此属性值的封装 if("".equals(paramValue) || null==paramValue){ continue; } /*根据表单的name值类取得对应的属性,这就是 为什么需要我们表单的name值要与实体类的属性 名对应的原因,我们可以根据这个属性的类型,来 确定setter方法的参数类型,并确定是否需要进 行类型装换*/ Field field = cls.getDeclaredField(paramName); //获取参数类型,没有包名,getSimpleName()此方法是去除包名的 String fieldType =field.getType().getSimpleName(); /*获取指定的操作方法,以满足反射的调用 使用字符串set+属性名的方式,并把属性的首字母 大写,正好对应我们属相的setter方法,参数类型 就是上面的field */ Method method = cls.getMethod("set"+initcap(paramName), field.getType()); //此处进行判断是否需要进行类型的转换 if("String".equals(fieldType)){ //执行具体set方法,并传入具体值 method.invoke(obj, paramValue); }else if("Integer".equals(fieldType) || "int".equals(fieldType)){ method.invoke(obj,Integer.parseInt(paramValue)); }else if("Double".equals(fieldType) || "double".equals(fieldType)){ method.invoke(obj,Double.parseDouble(paramValue)); }else if("Date".equals(fieldType)){ method.invoke(obj,new SimpleDateFormat("yyyy-MM-dd").parse(paramValue)); } } } //将属性名的首字母大写 private static String initcap(String value){ return value.substring(0,1).toUpperCase().concat(value.substring(1)); } }

    参数封装方法已完成,只需要在Servlet中调用即可

    package com.servlet; import com.entity.Student; import com.utils.BeanOperateTools; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "StudentServlet", urlPatterns = {"/studentServlet"}) public class StudentServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); //要存储表单数据的对象 Student stu = new Student(); try { //直接调用,传入要存储表单数据的对象,和request BeanOperateTools.setValueSimple(stu,req); } catch (Exception e){ e.printStackTrace(); } //将封好的数据存入request中, req.setAttribute("stu",stu); //跳转页面,查看封装的数据是否正确 req.getRequestDispatcher("show.jsp").forward(req,resp); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } }

    show.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${stu} </body> </html>

    写完这些我们在看一下springMVC的参数自动映射的条件:

    表单name属性的值必须与对象属性名相同必须提供属性公共的setter方法 现在知道为什么了吗!

    参数自动映射的具体过程,大致就这些,不知道你看明白了吗,当然,我们所写的与springMVC的相比,那就是,小巫見大巫、木棍挑战坦克,重申:此文章,只是让我们能够了解springMVC在进行参数封装的过程,对框架能够有一个更加深层的认知

    Processed: 0.022, SQL: 8