servlet自动获取前端页面提交数据

servlet自动获取前端页面jsp提交数据

  以下是本人在学习过程中,因前端页面提交参数过多,后台servlet封装实体类过于麻烦而写的一个工具类,应用于jsp/servlet数据提交后,基于MVC+MyBatis进行数据持久化的过程。这里只介绍页面到servlet(controller)提交数据封装对象的过程,MVC+MyBatis访问数据库不在这里介绍。

1.前端页面及代码

  1)前端表单页面构建(用于测试简单构建的页面有点丑陋哦~)

      servlet自动获取前端页面提交数据

  2)前端jsp页面代码

       这里使用了Ajax异步 get去除缓存方式提交表单。传统方式请自测,本人都已经测试过,在这里不做展示。

     注意:在Ajax提交表单部分使用了jQuery的serialize()序列化函数,初学者可参看jQuery的帮助文档。如不理解,可以在data部分使用“字符串”或json对象的方式进行常规方式提交数据。

 <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="jquery-1.11.1-min.js"></script>
<script type="text/javascript">
$(function(){
$("#submitBtn").click(function(){
$.ajax({
url:"${pageContext.request.contextPath }/testPage",
data:$("#formId").serialize(), //jQuery中的函数,序列化表单数据
type:"get",
cache:false,
success:function(jsonObj){
alert(jsonObj.msg);
$("#formId")[0].reset();//重置表单
}
})
});
}) </script>
</head>
<body>
<form id="formId">
ID:<input id="id" name="id"><br>
姓名:<input id="username" name="username"><br>
性别:<input id="sex" name="sex" ><br>
年龄:<input id="age" name="age" ><br>
价格:<input id="price" name="price"><br>
<input type="button" value="提交" id="submitBtn">
</form>
</body>
</html>

2.实体类

  5个属性and提供set/get方法

 package com.domain;

 public class Person {
String username;
String sex;
int age;
Double price;
Long id;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}

3.后台Servlet代码

  1)封装实体类对象

  这里只讲前端提交数据输出到控制台,证明数据已经获取并封装到对象中。

其中,p = (Person) EncapsulationUtil.getJavaBean(Person.class, request); 使用了封装体工具,为本人为偷懒所写,在后面提供源码。后面做详细解释。

  注意:前端提交数据和我们需要保存到数据库的数据不完全时,在servlet中拿到封装对象后可手动进行设置,如:数据的主键id一般我们采用UUID进行后台生成需要手动set进行设置。

 package com.controller;

 import java.io.IOException;
import java.util.HashMap;
import java.util.Map; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.domain.Person;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.utils.EncapsulationUtil; public class testPage extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//定义数据封装体的对象
Person p;
//定义用于返回json的数据存放集合
Map<String,Object> map = new HashMap<>(); try {
//获取前端页面表单提交的数据
p = (Person) EncapsulationUtil.getJavaBean(Person.class, request);
//打印封装体中的数据结果
System.out.println("ID---->"+p.getId()+"<-----");
System.out.println("姓名:---->"+p.getUsername()+"<-----");
System.out.println("年龄:---->"+p.getAge()+"<-----");
System.out.println("性别:"+p.getSex());
System.out.println("价格:"+p.getPrice());
map.put("msg", "提交成功"); } catch (Exception e1) {
e1.printStackTrace();
//当前的提交数据类型和实体类中数据格式不一致时,抛出异常
System.err.println("getMessage"+e1.getMessage());
//将异常信息保存到集合中,返回到前端
map.put("msg", e1.getMessage());
} //jackson插件,用于将map集合转化为json字符串
ObjectMapper ob = new ObjectMapper();
//返回json
request.setAttribute("json",ob.writeValueAsString(map) );
request.getRequestDispatcher("/json.jsp").forward(request, response); /* Map<String,Object> conditionMap = EncapsulationUtil.getMap(request); Set ketSet = conditionMap.keySet();
for (Object object : ketSet) {
String key = (String) object;
System.out.println(conditionMap.get(key));
}*/
} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
} }

 

 2)封装map集合对象(因在MVC+Mybatis中可能用到map结合,所以提供此方法)

  解释:a.这里不再展示如何使用此工具类封装map集合,实现比较简单。

       b.如想测试,将doGet方法中注释掉的代码放开,上面的代码注释掉即可,同样为数据到控制台。

       c.重点!此工具虽然定义了Map<String,Object> 由于页面通过http协议提交的参数通过request.getParameter()获取后为String类型,实际保存在map对象中的数据为Map<String,String>,如需要在后台获取String类型之外的数据格式,需要单独进行获取后转换类型。下面举一个分页查询中的小例子作为补充。其中利用到了Map即可中key相同时,value会覆盖的特性,以保证我们拿到的map集合对象是数据类型满足要求的。

  以下为分页查询中的例子,页码pageNo, 每页显示记录条数pageSize,跳过的记录数skipNo 应均为Integer类型而不是String类型,所以需要做特殊处理。如下 A 和 B 的对比

  A.传统手动接收参数进行封装(找的其他项目中的代码,只为展示使用方法)

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取页面数据
Integer pageNo=Integer.parseInt(request.getParameter("pageNo"));
Integer pageSize =Integer.parseInt(request.getParameter("pageSize"));
String name = request.getParameter("name");
String owner = request.getParameter("owner");
String type = request.getParameter("type");
String state = request.getParameter("state");
String startDate = request.getParameter("startDate");
String endDate = request.getParameter("endDate");
Integer skipNo = (pageNo-1)*pageSize; //封装数据集合
Map<String,Object> conditionMap = new HashMap<>();
conditionMap.put("pageNo", pageNo);
conditionMap.put("pageSize", pageSize);
conditionMap.put("name", name);
conditionMap.put("owner", owner);
conditionMap.put("type", type);
conditionMap.put("state", state);
conditionMap.put("startDate", startDate);
conditionMap.put("endDate", endDate);
conditionMap.put("skipNo", skipNo);
}

  B.封装工具进行接收参数

 @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取页面数据
Integer pageNo = Integer.parseInt(request.getParameter("pageNo"));
Integer pageSize = Integer.parseInt(request.getParameter("pageSize"));
Map<String,Object> conditionMap = EncapsulationUtil.getMap(request);
conditionMap.put("pageSize", pageSize);
conditionMap.put("skipNo", (pageNo-1)*pageSize); //创建Service代理对象
TransactionService ts = (TransactionService) ServiceFactory.getServiceProxy(new TransactionServiceImpl());
PaginationVO<Transaction> pv = ts.getPaginationVO(conditionMap);
//响应json
ResponseJSON.out(pv, request, response); }

4.封装体工具类

  1).工具类中已经对前端页面提交数据两端可能存在空白进行了处理,减少页面处理过程

  2). 重点!前端提交表单时,要求URL中name=value&name=value...中name部分(或者说表单中name属性的值)要和实体类中属性字段名保持一致,因为工具中封装原理是调用实体类中的set方法,因此实体类中需要提供标准的set方法。

  3).getJavaBean()方法可能会抛出异常,异常发生在前端提交数据和实体中字段类型不一致。如:实体类中年龄为int/Integer,前端提交时输入了“张三”等非法数据。因此最好在前端做表单验证,以保证数据的合法性。

 package com.utils;
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.http.HttpServletRequest; /**
* 获取请求参数封装对象的工具类
*
*/
public class EncapsulationUtil { private static int in;
private static float fl;
private static double d;
private static Integer integ;
private static Double doub;
private static Long lon;
/**
* 获取一个JavaBean,封装有request请求传递的参数
*
* @param claz
* 封装参数的实体类的Class
* @param request
* 接收数据的HttpServletRequest请求
* @return 封装有请求数据的JavaBean实体类
* @throws 当接收到的参数数据类型和实体类对应属性类型不一致时 抛出
* 异常信息:“数据格式有误!”
*/
public static Object getJavaBean(Class<?> claz, HttpServletRequest request) { // 1.获取请求中的参数名称
Enumeration<String> params = request.getParameterNames(); // 2.声明实体类的对象
Object jBeanObj = null; try {
jBeanObj = claz.newInstance(); // 初始化实体类对象 for (Enumeration<String> e = params; e.hasMoreElements();) {
// 3.遍历获取某一个参数名(属性)
String paramName = e.nextElement().toString();
if("_".equals(paramName)){
continue;
}
String paramValue = request.getParameter(paramName).trim(); // 4.构建set方法方法名
String setMethodName = "set" + paramName.substring(0, 1).toUpperCase() + paramName.substring(1); // 5.获取属性的Field对象
Field field = claz.getDeclaredField(paramName); // 6.获取属性的声明类型
Class<?> fieldType = field.getType(); // 7.获取set方法的Method对象 (方法名,参数类型的Class)
Method setMethodObj = claz.getDeclaredMethod(setMethodName, field.getType());
setMethodObj.setAccessible(true); // 8.判断属性类型,调用JavaBean的set方法
if (Integer.class.equals(fieldType)) { if("".equals(paramValue)){
setMethodObj.invoke(jBeanObj,integ);
}else{
setMethodObj.invoke(jBeanObj, Integer.valueOf(paramValue));
} } else if (Long.class.equals(fieldType)) { if("".equals(paramValue)){
setMethodObj.invoke(jBeanObj,lon);
}else{
setMethodObj.invoke(jBeanObj, Long.parseLong(paramValue));
} } else if (Double.class.equals(fieldType)) { if("".equals(paramValue)){
setMethodObj.invoke(jBeanObj,doub);
}else{
setMethodObj.invoke(jBeanObj, Double.parseDouble(paramValue));
} } else if (String.class.equals(fieldType)){ setMethodObj.invoke(jBeanObj, paramValue); } else if(int.class.equals(fieldType)){ if("".equals(paramValue)){
setMethodObj.invoke(jBeanObj,in);
}else{
setMethodObj.invoke(jBeanObj, Integer.parseInt(paramValue));
}
} else if(float.class.equals(fieldType)){ if("".equals(paramValue)){
setMethodObj.invoke(jBeanObj,fl);
}else{
setMethodObj.invoke(jBeanObj, Float.parseFloat(paramValue));
} } else if(double.class.equals(fieldType)){ if("".equals(paramValue)){
setMethodObj.invoke(jBeanObj,d);
}else{
setMethodObj.invoke(jBeanObj, Double.parseDouble(paramValue));
}
} }
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException | NoSuchFieldException | InstantiationException e) {
e.printStackTrace();
throw new NumberFormatException("数据格式错误,请核对!");
} // 9.返回封装对象
return jBeanObj;
} /**
* 获取请求数据的Map集合封装体
*
* @param request
* 接收数据的HttpServletRequest请求
* @return 返回封装请求中数据的Map<String ,Object>
*/
public static Map<String, Object> getMap(HttpServletRequest request) {
// 0.创建Map集合
Map<String, Object> map = new HashMap<String, Object>(); // 1.获取请求中的参数名称
Enumeration<String> params = request.getParameterNames(); for (Enumeration<String> e = params; e.hasMoreElements();) {
// 2.遍历获取某一个参数名称
String paramName = e.nextElement().toString();
// 3.获取参数值
String paramValue = request.getParameter(paramName).trim();
// 4.封装数据
map.put(paramName, paramValue);
}
// 5.返回封装体集合
return map;
} private EncapsulationUtil() {
}
}

5.工具目录图

  其中ajax部分json.jsp如下: 

<%@ page language="java" contentType="text/json; charset=UTF-8"
pageEncoding="UTF-8"%>
${json}

  工具目录图(测试一切从简,请勿追问包结构不完整之类问题)

    servlet自动获取前端页面提交数据

6.效果展示

  将工程发布到Tomcat中,进行访问http://localhost:8080/reflect/test.jsp

  1)前端提交正常数据

    前端页面

    servlet自动获取前端页面提交数据

    点击提交后,后台控制台输出及前端显示

    servlet自动获取前端页面提交数据

  2)前端提交非法数据时(未做表单验证)

    年龄应为int类型,底层使用了Integer.valueOf(paramValue)因此会发生数据格式换行异常。这是需要注意的地方!!特殊地方最好做表单验证,这是测试demo就不再丰富。

    servlet自动获取前端页面提交数据

说明:本例中工具类纯属个人学习过程中在不使用Spring等框架的前提下 为偷懒所写,如使用生产环境发生问题,概不负责!

转载请注明出处,谢谢!^.^

    

上一篇:S关于使用QL声明 找出同时满足多个tag拍摄条件设置算法


下一篇:Saiku控制页面展示的数据过长自动换行(二十四)