您的位置:首页 > 编程语言 > Java开发

java 反射机制-学习笔记(4)

2017-10-30 21:20 555 查看

servlet 自定义反射

如果在jsp 页面直接写 javaBean 标签会显得重复啰嗦,解决这个问题就是要把它单独作为一个组件。先看在servlet 中通过反射接受、设置参数的例子。

继续上次的项目添加一个 StudentServlet 类:

package cn.lyx.servlet;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Enumeration;
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 cn.lyx.reflact.Student;
@WebServlet(urlPatterns={"/jsp/StudentServlet"})
public class StudentServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
Object student = null;
try {
// 取得Class 对象
Class<?> cls = Class.forName("cn.lyx.reflact.Student");
student = cls.newInstance(); // 实例化对象
// 取得所有输入的参数名称
Enumeration<String> enu = req.getParameterNames();
// 遍历获取输入的参数
while(enu.hasMoreElements()){
String paramName = enu.nextElement();
String paramValue = req.getParameter(paramName);
// 通过反射获得指定属性
// 因为输入 的参数名称和对象属性名称一致,可以把属性和输出参数名称一一对应操作。
// 取得属性的类型是为了取得参数的类型,以确定method 方法,和是否转型
Field field = cls.getDeclaredField(paramName);  // 获得指定参数
// 首字母大写,比如 name 的set 方法名是  setName(首字母大写)
String firstUp = paramName.substring(0,1).toUpperCase()
.concat(paramName.substring(1).toLowerCase());
// 通过反射获得指定方法
// 取得set操作方法,满足反射调用
Method method = cls.getMethod("set" + firstUp, field.getType());
// 根据不同类型进行数据的转换,同时调用setter 设置数据
String fiedlType = field.getType().getSimpleName().toLowerCase(); //
switch (fiedlType) {
case "string":
method.invoke(student, paramValue);  // 通过反射调用方法
break;
case "int":
method.invoke(student, Integer.parseInt(paramValue));
break;
case "integer":
method.invoke(student, Integer.parseInt(paramValue));
break;
case "double":
method.invoke(student, Double.parseDouble(paramValue));
break;
default:
break;
}

}

} catch ( Exception  e) {

e.printStackTrace();
}
req.setAttribute("student", student);
req.getRequestDispatcher("student_insert_do.jsp").forward(req, resp);
}
}


可以看到StudentServlet 类中通过反射的方式完成了 Student 的实例化以及设置属性值。

修改 index.jsp ,只是换了请求action 的值,和servlet 中的urlPatterns值对应。 如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>首页</title>
</head>
<body>
<%
request.setCharacterEncoding("UTF-8");
%>
<form action="StudentServlet" method="post">
姓名:<input type="text" name="name"><br>
年龄:<input type="text" name="age"><br>
成绩:<input type="text" name="score"><br>
<input type="submit" value="输入">
<input type="reset"  value="重置">
</form>
</body>
</html>


student_insert_do.jsp 修改比较大,去掉所有javaBean标签,留下简洁的 ${}取值。 修改如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<% request.setCharacterEncoding("UTF-8"); %>
<html>
<head>
<title>Java Bean 操作</title>
</head>
<body>
<h5>姓名 : ${student.name}</h5>
<h5>年龄 : ${student.age}</h5>
<h5>成绩 : ${student.score}</h5>
</body>
</html>


如之前一样测试,结果正常。

反射组件封装

上面的反射部分直接写在servlet 中,假如有多个servlet那么需要一个个去重复写,不符合可复用的开发原则。那么就需要单独封装在工具类中。

新建一个工具类 :

package cn.lyx.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Enumeration;

import javax.servlet.ServletRequest;
/**
* 利用反射进行所有请求参数设置,
* @author ShayneLee
*
*/
public class BeanOperateTools {
/**
*
* @param obj 传递过来要操作的对象
* @param req 传递输入的参数过来
* @throws Exception
*/
public static void setValueSimple(Object obj, ServletRequest req)
throws Exception{
// 取得Class 对象
Class<?> cls = obj.getClass();
// 这里把之前的那个实例化语句删除。因为传递过来的对象已经被实例化过了,这里就不用重复实例化
// 取得所有输入的参数名称
Enumeration<String> enu = req.getParameterNames();
// 遍历获取输入的参数
while(enu.hasMoreElements()){
String paramName = enu.nextElement();
String paramValue = req.getParameter(paramName);
// 因为输入 的参数名称和对象属性名称一致,可以把属性和输出参数名称一一对应操作。
// 取得属性的类型是为了取得参数的类型,以确定method 方法,和是否转型
Field field = cls.getDeclaredField(paramName);  // 获得指定参数
// 首字母大写
String firstUp = paramName.substring(0,1).toUpperCase()
.concat(paramName.substring(1).toLowerCase());
// 取得set操作方法,满足反射调用
Method method = cls.getMethod("set" + firstUp, field.getType());
// 根据类型进行数据的装换,同时调用setter 设置数据
String fiedlType = field.getType().getSimpleName().toLowerCase();
switch (fiedlType) {
case "string":
method.invoke(obj, paramValue);  //
break;
case "int":
method.invoke(obj, Integer.parseInt(paramValue));
break;
case "integer":
method.invoke(obj, Integer.parseInt(paramValue));
break;
case "double":
method.invoke(obj, Double.parseDouble(paramValue));
break;
default:
break;
}

}
}
}


这个工具类直接把 servlet 类中的反射部分复制过来。

修改StudentServlet类如下:

package cn.lyx.servlet;

import java.io.IOException;
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 cn.lyx.reflact.Student;
import cn.lyx.util.BeanOperateTools;

@WebServlet(urlPatterns={"/jsp/StudentServlet"})
public class StudentServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws Servl
9d59
etException, IOException {
req.setCharacterEncoding("UTF-8");
Student student = new Student();
// 调用反射工具类
try {
BeanOperateTools.setValueSimple(student, req);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
req.setAttribute("student", student);
req.getRequestDispatcher("student_insert_do.jsp").forward(req, resp);
}
}


看到这样的 servlet 类,是不是感觉世界清静了很多。

如同之前的测试,一切正常。

参考:魔乐科技-李兴华-java 反射机制
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: