首页 课程 师资 教程 报名

Java反射自动赋值详解

  • 2021-06-02 15:56:17
  • 472次 星辉

自动赋值操作

所有的开发中,几乎都会将用户传递的数据转换为简单Java类的形式进行操作。

那么现在可以继续采用之前的方式进行操作,可是又一点比较麻烦;

在BeanOperate类里面的构造方法有两个;

怎么区分传递来的内容是使用数组接收还是使用单个字符串接收呢?

范例:定义一个页面index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'MyJsp.jsp' starting page</title>
 
  </head>
  
  <body>
    <form action="dept/insert" method="post">
      部门编号:<input type="text" name="dept.deptno" id="dept.deptno" value="10">
      部门名称:<input type="text" name="dept.dname" id="dept.dname" value="开发部">
      位置字段:<input type="checkboc" name="dept.loc" id="dept.loc" value="1">第1位置
                <input type="checkboc" name="dept.loc" id="dept.loc" value="2">第2位置
                <input type="checkboc" name="dept.loc" id="dept.loc" value="3">第3位置
                <input type="checkboc" name="dept.loc" id="dept.loc" value="4">第4位置
                <input type="checkboc" name="dept.loc" id="dept.loc" value="5">第5位置
                <input type="checkboc" name="dept.loc" id="dept.loc" value="6">第6位置
      公司名字:<input type="text" name="dept.company.title" id="dept.company.title" value="hello公司">
      <input type="submit" value="提交">
      <input type="reset" value="重置">
  </body>
</html>

所有的Servlet都需要进行提交参数与简单Java类的转换。

现在可以假设只有带“.”才需要实现自动的转换操作。

范例:在doGet()方法里面进行存在

public abstract class DispatcherServlet extends HttpServlet{
    private static final String PAGES_BASENAME="Pages";
    private static final String MESSAGES_BASENAME="Messages";
    
    private ResourceBundle pagesResource;
    private ResourceBundle messagesResource;
    protected HttpServletRequest request;
    protected HttpServletResponse response;
    
    public void init()throws ServletException{
        this.pagesResource=ResourceBundle.getBundle(
        PAGES_BASENAME,Locale.getDefault());
        this.messagesResource=ResourceBundle.getBundle(
        MESSAGES_BASENAME_BASENAME,Locale.getDefault());
    }
    /*
    取得在Pages.properties文件里面定义的访问路径
    key 访问路径的key
    return 配置文件中的路径内容,如果没有返回null
    */
    public String getPath(String key){
        return this.pagesResource.getString(key);
    }
    /*
    取得Messages.properties文件中的配置文字信息
    key 访问文字信息的key
    args 所有占位符的内容
    return 配置文件中的内容,并且是组合后的结果,如果没有返回null
    */
    public String getMsg(String key,String ...args){
        String note=this.messagesResource.getString(key);
        if(args.length>0||this.getTitle()==null){//传递了参数内容
            return MessageFormat.format(note,args);
        }else{
            return MessageFormat.format(note,this.getTitle());
        }    
    }
    /*
    交由不同的子类来实现,可以由子类来设置统一的占位符提示信息名称标记
    return 返回不同子类的描述信息
    */
    public abstract String getTitle();
    public void doGet(HttpServletRequest request,HttpServletResponse response)
    throws ServletException,IOException{
        this.request=request;
        this.response=response;
        String path=this.getPath("errors.page");
        String status=request.getRequestURI().substring(
                        request.getRequestURI().lastIndexOf("/")+1);
        //现在可以找到当前类对象this,以及要调用的方法名称status,可以利用反射进行调用
        if(status!=null&&status.length()>0){
            //取得全部的请求参数名称,之所以需要名称,主要是确定自动赋值的存在
            Enumbertion<String> enu=request.getParameterNames();
            while(enu.hasMoreElements()){  //循环所有的参数名称
                String paramName=enu.nextElement();
                if(paramName.contains(".")){//按照简单Java类处理
                    AttributeType at=new AttributeType(this,paramName);
                    if(at.getFieldType().contains("[]")){  //按照数组的方式进行处理
                        BeanOperate bo=new BeanOperate(this,
                        paramName,request.getParameterValues(paramName));
                    }else{//按照单个字符串的方式进行处理
                        BeanOperate bo=new BeanOperate(this,
                        paramName,request.getParameter(paramName));
                    }
                }
            }
            try{ //只有将对应的数据准备完毕了,才可以执行以下方法
                Method method=this.getClass().getMethod(status);
                path=(String)method.invoke(this);//反射调用方法
            }catch(Exception e){
                e.printStackTrace();
            }
        }
        request.getRequestDispatcher(path).forward(request,response);
    }
    public void doPost(HttpServletRequest request,HttpServletResponse response)
    throws ServletException,IOException{
        this.doGet(request,response);
    }
}

首先要取得所有的提交参数以及对应的内容。

但是现在对于提交参数会产生以下情况;

我们无法去区分出是使用request.getParameter()还是request.getParamerValues()接收参数,

这样就无法确定使用哪一个BeanOperate类的构造;

有些参数可能不需要进行简单Java类的处理。

但是现在的程序之中并没有解决那里使用getParameter()与getParameterValue()两个方法的操作。

唯一能做的区分只有一种形式,根据参数的名称挖掘数据类型,可以再定义一个专门的处理类,进行属性的处理。

AttributeType.java

public class AttributeType{
    private Object currentObject;  //当前的操作对象
    private String attribute;     //属性的字符串描述
    private Field field;      //属性的成员
    
    public AttributeType(Object currentObject,String attribute){
        this.currentObject=currentObject;
        this.attribute =attribute;
        this.handleParameter();
    }
    private void handleParameter(){针对于传入数据进行处理
        try{
        String result[]=this.attribute.split("\\.");
        if(result.length==2){//现在表示的是单级操作
        //对于类中的getter方法上是不存在参数的,所以参数类型为空
        Method getMet=this.currentObject.getClass()
        .getMethod("get"+StringUtils.initcap(result[0]));
        this.currentObject=getMet.invoke(this.currentObject);//调用了getter方法
        Field field=ret.getClass().getDeclareField(result[1]);//取得对象成员
        }else{ //现在表示的多级操作
            for(int x=0;x<result.length;x++){
                //System.out.println("x="+x+"="this.currentObject);
                //必须知道当前操作的成员对象,因为只要有对象存在才可以找到属性类型,才可以调用setter方法
                this.field=this.currentObject.getClass().getDeclareField(result[x]);
                //System.out.println(this.field.getName());
                if(x<result.length-1){//现在不是最后一块组成,还有内容
                Method met=this.currentObject.getClass()
                .getMethod("get"+StringUtils.initcap(result[x]));
                    this.currentObject=met.invoke(this.currentObject);
            }
        }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    public Field getField(){
        return this.field;
    }
    public String getFieldType(){
        return this.field.getType().getSimpleName();
    }
}
@SuppressWarnings("serial")
@WebServlet(urlPatterns="dept/*")
public class DeptServlet extends DispatcherServlet{
    private Dept  dept=new Dept();
    public String insert(){
        System.out.println("======DeptServlet--insert()==========");
        return "";
    }
    public String update(){
        System.out.println("======DeptServlet--update()==========");
        return "";
    }
    public String getTitle(){
        return "部门";
    }
    public Dept getDept(){
        return dept;
    }
    //覆写dept略
}
public class  Dept{
   private String dname;
   private Integer deptno;
   private Integer loc[];
   private Company company=new Company();//必须实例化
   public void setDeptno(Integer deptno){
       this.deptno=deptno;
   }
   public Integer getDeptno(){
       return deptno;
   }
   public void setDname(String dname){
       this.dname=dname;
   }
   public String getDname(){
       return dname;
   }
   public Company getCompany(){
       return company;
   }
}
public class BeanOpreate{
    private Object currentObj;//表示当前程序的保存对象
    private String attribute;//要操作的属性
    private String value;//要操作的内容
    private String arrayValue[];//要操作的数组内容
    private Field field;//表示要操作的成员对象
    /*
    进行操作数据的接收,接收后才可以进行数据的设置操作
    obj表示当前要操作次功能的类对象
    attribute包含了 "对象.属性.属性... " 字符串
    value 表示属性内容
    */
    public BeanOpreate(Object Obj,String attribute,String arrayValue[]){
        this.currentObj=obj;//保存当前的操作对象
        this.attribute=attribute;
        this.arrayValue=arrayValue;
        this.handleParameter();
        this.setValue();
    }
//进行数组数据的操作
    public BeanOpreate(Object Obj,String attribute,String value[]){
        this.currentObj=obj;//保存当前的操作对象
        this.attribute=attribute;
        this.value=value;
        this.handleParameter();
        this.setValue();
    }
    private void handleParameter(){针对于传入数据进行处理
        try{
        String result[]=this.attribute.split("\\.");
        if(result.length==2){//现在表示的是单级操作
        //对于类中的getter方法上是不存在参数的,所以参数类型为空
        Method getMet=this.currentObj.getClass()
        .getMethod("get"+StringUtils.initcap(result[0]));
        this.currentObj=getMet.invoke(this.currentObj);//调用了getter方法
        Field field=ret.getClass().getDeclareField(result[1]);//取得对象成员
        }else{ //现在表示的多级操作
            for(int x=0;x<result.length;x++){
                //System.out.println("x="+x+"="this.currentObj);
                //必须知道当前操作的成员对象,因为只要有对象存在才可以找到属性类型,才可以调用setter方法
                this.field=this.currentObj.getClass().getDeclareField(result[x]);
                //System.out.println(this.field.getName());
                if(x<result.length-1){//现在不是最后一块组成,还有内容
                Method met=this.currentObj.getClass()
                .getMethod("get"+StringUtils.initcap(result[x]));
                    this.currentObj=met.invoke(this.currentObj);
            }
        }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    private void setValue(){ //定义一个专门设置属性内容的方法,调用的setter操作
    try{
        Method setMet=this.currentObj.getClass().getMethod("set"+StringUtils
        .initcap(this.field.getName()),this.field.getType());
        setMet.invoke(this.currentObj,this.value);
        String type=this.field.getType().getSimpleName();//取得数据类型
    if("int".equalsIgnoreCase(type)||"integer".equalsIgnoreCase(type)){
        if(this.value.matches("\\d+")){
            setMet.invoke(this.currentObj,Integer.parseInt(this.value));
        }
    }else if("double".equalsIgnoreCase(type)){
        if(this.value.matches("\\d+(\\.\\d+)?")){
        setMet.invoke(this.currentObj,Double.parseDouble(this.value));
        }
    }else if("String".equalsIgnoreCase(type)){
        setMet.invoke(this.currentObj,this.value);
    }else if("date".equalsIgnoreCase(type)){
        if(this.value.matches("\\d{4}-\\d{2}-\\d{2}")){
            setMet.invoke(this.currentObj,new SimpleDateFormat("yyyy-MM-dd")
        .parse(this.value));
        }
        if(this.value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")){
            setMet.invoke(this.currentObj,new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
            .parse(this.value));
        }
    }else if("string[]".equalsIgnoreCase(type)){ //字符串数组
        setMet.invoke(this.currentObj,new Object[]{this.arrayValue});
    }else if("double[]".equals(type)){
        double temp[]=new double[this.arrayValue.length];
        for(int x=0;x<temp.length;x++){
            if(this.arrayValue[x].matches("\\d+(\\.\\d+)?")){
            temp[x]=Double.parseInt(this.arrayValue[x]);
            }
        }        
        setMet.invoke(this.currentObj,new Object[]{temp});
    }else if("Double[]".equals(type)){
        Double temp[]=new Double[this.arrayValue.length];
        for(int x=0;x<temp.length;x++){
            if(this.arrayValue[x].matches("\\d+(\\.\\d+)?")){
            temp[x]=Double.parseInt(this.arrayValue[x]);
            }
        }        
        setMet.invoke(this.currentObj,new Object[]{temp});
    }
    }catch(Exception e){
        e.printStackTrace();
    }
    }
}

以上就是星辉小编介绍的"Java反射自动赋值详解",希望对大家有帮助,如有疑问,请在线咨询,有专业老师随时为您服务。

选你想看

你适合学Java吗?4大专业测评方法

代码逻辑 吸收能力 技术学习能力 综合素质

先测评确定适合在学习

在线申请免费测试名额
价值1998元实验班免费学
姓名
手机
提交