实现java表单提交时请求参数与dto的映射

本文介绍了一种在Spring MVC框架中优化请求参数绑定的方法,利用Java反射技术减少模板式代码,提高开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    一般在servlet或controller里获取前台请求的数据时时通过request.getParam的方式获取,此方式会产生大量的模板式的重复代码,整体代码也不简洁。为此各种框架都做了一些处理,使得开发人员从这种无聊的工作中解放出来,比如spring在handle方法中增加object参数,struct在action的execute方法中增加form参数。应用系统开发人员直接从object、form中获取所需数据。今天想分享下自己在实现这种映射时的思路和具体代码。

    主要使用的技术就是java的反射编程(反射和动态代理是java技术的一大亮点,相当好用)。主要思路是通过编写一个抽象controller父类,并增加handleRequestForSpringWeb抽象方法,所有业务controller继承此父类,并重写handleRequestForSpringWeb,在该方法中处理业务逻辑,而spring提供的原有的抽象方法handleRequestInternal则用来处理请求参数与dto的绑定。绑定时的原则是先确认dto属性(具体如convertMap),再根据dto属性去request中获取参数值,并赋值dto属性中。

这里以重写spring的abstractcontroller为例,代码不算多,具体如下:

 


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import dto.AbstractDTO;

public abstract class SpringWebAbstractController extends AbstractController {
	private String dto;
	public String getDto() {
		return dto;
	}
	public void setDto(String dto)throws Exception {
		this.dto = dto;
	}
	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		request.setCharacterEncoding("gbk");
		response.setCharacterEncoding("utf-8");
		AbstractDTO obj = (AbstractDTO)this.build(request);
		return handleRequestForSpringWeb(request,response,obj);
	}
	
	//此抽象方法新增dto参数,方便取值,所有继承此类的controller,需配置dto属性
	//若不配置,则不可使用dto
	<span style="color:#ff0000;">public abstract ModelAndView handleRequestForSpringWeb(HttpServletRequest request,
			HttpServletResponse response,AbstractDTO abstractDTO)throws Exception</span>; 
	
	
	private Object build(ServletRequest request)throws Exception{
		Object instance = null;
		try {
			if(dto==null||dto.trim().equals(""))
				return null;
			Class<?> clazz = Class.forName(dto);
			instance = clazz.newInstance();
			Field fields[] = clazz.getFields();
			Map<String,Class<?>> fieldMap = convertMap(fields);
			
			Enumeration<?> enumeration = request.getParameterNames();
			while(enumeration.hasMoreElements()){
				String paramKey = (String)enumeration.nextElement();
				String paramValues[] = request.getParameterValues(paramKey);
				Class fieldClazz = fieldMap.get(paramKey);
				if(fieldClazz==null){
					//这里应该报错,提示开发人员注意dto与请求参数保持一致。
					continue;
				}
				setProperty(instance,fieldClazz,paramKey,paramValues);
			}
		} catch (Exception e) {
			throw e;
		}
		return instance;
	}
	/**
	 *把DTO的field按照key=name和value=class的形式转成map结构 
	 */
	private Map<String,Class<?>> convertMap(Field fields[]){
		Map<String,Class<?>> fieldMap = new HashMap<String,Class<?>>();
		for(Field field:fields){
			String key = field.getName();
			Class<?> value = field.getType();
			fieldMap.put(key, value);
		}
		return fieldMap;
	}
	private void setProperty(Object instance,Class fieldClass,String key,String values[]) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		String methodName = "set"+key.substring(0, 1).toUpperCase()+key.substring(1, key.length());
		try {
			Method method = instance.getClass().getMethod(methodName, fieldClass);
			if(fieldClass.getName().equals("java.lang.String")){
				method.invoke(instance, new Object[]{values[0]});
			}else{
				method.invoke(instance, new Object[]{values});
			}
		} catch (SecurityException e) {
			e.printStackTrace<span style="color:#cc0000;">();//异常需要处理
</span>		} catch (NoSuchMethodException e) {
			e.printStackTrace();<span style="color:#cc0000;">//异常需要处理</span>
		}
	}
	public void init(){
		System.out.println(this.getClass().getName()+";dto="+this.getDto());
	}
}

 

改进:

此代码有两个地方可以优化的地方

1、dto属性类型

目前的dto仅支持了string和string数组(这个也是request中的请求参数类型),但是实际中可能需要转成date,int甚至其他dto等多层次结构。可以在代码中再进行细粒度的区分处理。对于需要再转成其他dto多层结构,可以考虑根据request中key和dto路径映射。比如PersonDTO下有年龄(age)、男女(sex)等属性,也有CompanyDTO(公司)。

那么request中的参数就写成age=15,sex=男,companyDTO.companyName=xxx,companyDTO.companyAddress=xxx。映射时,先截取再处理。

2、dto改成map

dto毕竟是需要在系统中特别编写,而实际处理时可能希望通过map去映射,如果通过map则思路就要变成根据request的参数去赋值map了

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值