简介

MVC是现在项目开发之中首要使用得架构模式,使用MVC可以有效的实现后台程序与前台HTML代码的有效分离,同时可以方便的进行团队的分工合作。

以用户登录验证为例观察开发中的两种模式:

来观察软件分层设计:

以上的实现就属于MVC,MVC有三个组成部分:

  • M(Model 模型层):指可以重复执行的Java程序类,在进行远程开发设计的时候,就是将模型层的部分内容单独抽取出来(业务、数据层);
  • V(view 视图层):进行用户界面展示以及信息提示用的,这些信息往往都是Servlet传递过来的,往往使用的都是request属性范围;
  • C(Controller 控制层):接收用户请求处理参数、进行参数的验证、业务层调用以及页面跳转操作,是整个项目的中心;

在MVC标准里面,用户所发送的所有的请求都必须通过控制层跳转到显示层,即用户的请求不允许连接到JSP页面中的。实际开发中,可能不按照标准来。

多业务实现分析

Java Web核心技术:JSP、Servlet、JSTL、EL、MVC设计模式,如果要想进行一个WEB项目的开发需要考虑以下问题:

  • 如何让代码实现重用?
  • 如果让一个开发具备标准型?
  • 更简单、轻松的实现项目开发?

MVC设计的本质在于:用户的所有的请求一定要先交给控制层完成,控制层要跳转到指定的显示页面上,而显示页面进行进一步的数据提交,数据提交给控制层。一个基础的CRUD,就可能需要六个Servlet程序,实际开发中就更多的基础操作,Servlet程序代码多还大量重复。

如果要进行合理的设计,就需要多业务设计,即一个Servlet处理多个程序的功能。

多业务设计

例如一个部门管理程序,如果按照之前的设计就需要:DeptAddPreServlet、DeptAddServlet、DeptEditPreServlet、DeptEditServlet、DeptListServlet、DeptDeleteServlet六个Servlet程序,多业务设计就是将六个的实现功能,用一个Servlet代替。如果要实现就需要定义方法来完成,需要定义六个操作方法,这六个方法针对不同的业务操作。

需要知道:Servlet是根据doXxx()来区分不同线程的,而不是Servlet类对象完成的,Servlet属于单实例。通过范例观察这个观点。

范例:Servlet线程

package cn.ren.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;@SuppressWarnings("serial")
@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {private String msg = null ; // 定义一个变量定义在Servlet之中@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {if(req.getParameter("msg") != null) {this.msg = req.getParameter("msg");}System.out.println("******* msg = " + this.msg);}
}

第一个线程(用户请求):http://localhost/MyDispatcherServlet/MyServlet?msg=ren 结果 : msg = ren

第二个线程(用户请求):http://localhost/MyDispatcherServlet/MyServlet  结果 : msg = ren

但是如果使用不同的浏览器访问,就得到不同的Session,msg依然一样。

一般来说系统架构人员设计的是:DispatcherServlet,使用者操作DeptXxx,所有的前端MVC的开发框架就是处理中间的Servlet程序类。

Javassist开发包支持(用于获取参数名称)

要想做中间Servlet程序类,首先要解决的是参数的接收问题 。不管是否使用MVC设计模式,都会面临一个最为实际的开发问题:大部分都需要将用户的请求操作转化为VO类进行操作。之所以使用VO处理,主要的目的它可以和表对应,而且业务层接收VO会更加的方便。一般来说所有的VO类对象的创建都需要使用一系列的或者说大量的request.getParameter()操作一行行进行接收,如果表单参数多就难受了。那么就需要解决参数传递的问题。

下面以部门添加的控制层业务操作为例:

如现在关键的是取得参数名称,取得参数名称就可以使用request.getParameter()获取参数值,然后将参数值传进add()中调用add方法。我们知道反射只能获取参数的类型,而不能获取参数的名称。这个时候就需要Javassist开发包支持。下载地址:http://www.javassist.org/

范例:取得参数名称

package cn.ren.util;import java.lang.reflect.Method;
import java.lang.reflect.Modifier;import cn.ren.action.DeptAction;
import cn.ren.util.bean.MethodUtil;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;public class GetParameterName {public static final String METHOD_NAME = "add" ; // 要操作的方法 public static void main(String[] args) throws Exception {Class<?> cls = DeptAction.class;   // 必须有Class对象,有了Class对象才能找到ClassLoaderMethod method = MethodUtil.getMethod(cls, METHOD_NAME) ;Class<?> params [] = method.getParameterTypes() ; ClassPool classPool = ClassPool.getDefault() ;CtClass ctClass = classPool.get(cls.getName()) ; // 要操作类的字节码文件CtMethod ctMethod = ctClass.getDeclaredMethod(METHOD_NAME) ;  // 取得要操作的方法对象MethodInfo methodInfo = ctMethod.getMethodInfo() ; // 取得方法的信息// 以上取得方法的相关信息项CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); // 获取代码的属性LocalVariableAttribute attribute = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag) ;  // 取得属性标签(名称)int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1 ; // 要考虑方法中带有static标志的问题for(int i = 0; i < params.length; i ++) {System.out.println(attribute.variableName(i + pos));}}
}
package cn.ren.util.bean;
import java.lang.reflect.Method;
public class MethodUtil {private MethodUtil () {}/*** 取得指定类中指定方法的对象,关键是取得的时候并不知道方法中的参数类型* @param cls  操作的Class类对象* @param methodName 方法名称* @return    如果取得方法,则以Method对象返回,没有则返回null;*/public static Method getMethod(Class<?> cls,String methodName) {Method methodResult [] = cls.getMethods() ;for(int x = 0; x < methodResult.length; x ++) {if(methodName.equals(methodResult[x].getName())) {return methodResult[x] ;}}return null;}
}
package cn.ren.action;import cn.ren.vo.Dept;public class DeptAction {public String add(String attr, Integer age, Dept dept) {return "hello" ;}
}
package cn.ren.vo;import java.io.Serializable;@SuppressWarnings("serial")
public class Dept implements Serializable {private Integer deptno;private String dname;private String loc;public Integer getDeptno() {return deptno;}public void setDeptno(Integer deptno) {this.deptno = deptno;}public String getDname() {return dname;}public void setDname(String dname) {this.dname = dname;}public String getLoc() {return loc;}public void setLoc(String loc) {this.loc = loc;}}

总结:Java的反射实现安全处理操作,Spring开发框架中也有此开发包的应用;

路径拆分

一个项目中可能有很多个模块:Dept、Emp、Member.....,每一个模块都是一个独立的程序类,该类进行各种操作与方法的配置。这些程序类下面用Action来描述,用户的请求的处理需要经过DispatcherServlet才能到达各个Action中。即DispatcherServlet需要接收所有的用户请求,那么只能对用户的请求路径进行规范:

例如:http://localhost/MyDispatcherServlet /pages/back/admin/dept/dept ! list.action

所有要调用的Action的类名称:/pages/back/admin/dept/dept;

方法名称:list.action

路径拆分类:RequestUrlUtils 关系

范例:路径拆分

package cn.ren.util.web;import javax.servlet.http.HttpServletRequest;public class ResquestUrlUtil {private ResquestUrlUtil () {} /*** 进行路径的拆分,拆分出要操作的Action路径和方法名称 * @param request 包含所有的请求信息,通过此对象获取路径信息* @return   返回两个结果: 0 = 访问Action路径、1 = 方法名称*/public static String[] splitUrl(HttpServletRequest request) {String uri = request.getRequestURI().replace(request.getContextPath(), "") ;String result [] = uri.split("!") ;String str [] = new String [] {result[0], result[1].substring(0, result[1].indexOf("."))} ;return str ;}
}

配置程序Action

1、定义ModelAndView的工具类,该类保存跳转路径以及配置

package cn.ren.util.web;public class ModelAndView {private String url ;public ModelAndView(){}public ModelAndView(String url) {this.url = url ;}public void setUrl(String url) {this.url = url;}public String getUrl() {return url;}
}

2、Action是由开发者设计并使用,而不是整个软件架构设计者去考虑的问题。

在cn.ren.action包中定义一个EmpAction类。

package cn.ren.action;import cn.ren.util.web.ModelAndView;
/*** 开发者才会关注此处的程序类* @author ren**/
public class EmpAction {public EmpAction() {System.out.println("** EmpAction实例化 ");}public void show() {System.out.println("*** 无返回值 ");}public ModelAndView addPre() { // 无参的操作ModelAndView mav = new ModelAndView("/pages/back/admin/emp/emp_add.jsp") ;// 中间可能是你的一些业务的操作方法调用return mav ;}
}

3、使用资源文件action.propties将路径与EmpActio联系起来

/pages/back/admin/emp/EmpAction=cn.ren.action.EmpAction

4、定义专门的类处理反射方法的调用,以及Action类的实例化对象

package cn.ren.util.web;import java.lang.reflect.Method;
import java.util.Arrays;import cn.ren.util.MessageUtil;
import cn.ren.util.bean.MethodUtil;public class ActionBeanUtil {private static final MessageUtil ACTION_MESSAGE = new MessageUtil("cn.ren.util.message.action");private ActionBeanUtil() {}/*** 进行指定的Action对象实例化,以及方法的反射调用* @param uriResult 包含:Action程序的key、方法名称* @return*/public static ModelAndView actionHandle(String uriResult[]) throws Exception {String className = ACTION_MESSAGE.getText(uriResult[0]) ;Class<?> actionClass = Class.forName(className);Object actionObj = actionClass.getDeclaredConstructor().newInstance();  // 对象实例化 Method actionMethod = MethodUtil.getMethod(actionClass, uriResult[1]) ; // 获取方法System.out.println(uriResult[1]);if(actionMethod.getParameterTypes().length == 0) { // 无参数Object retObj = actionMethod.invoke(actionObj) ; // 没有参数判断if(retObj instanceof ModelAndView ) {return (ModelAndView) retObj ; }} else { // 有参数}return null ;}
}

改善ModelAndView

1、在编写ActionBeanUtil程序类,如果没有返回值,则直接返回null

针对于返回路径的配置,Dispatcher里面只需要取得跳转路径即可,它不应该关注ModelAndView的细节,而ActionBeanUtil类负责ModelAndView。

2、对ModelAndView设置属性

第一种:用户自己传递属性名称、内容;

第二种:业务层返回Map集合,此时最好的可以将Map集合自动的把Key作为属性名称、value作为属性内容;

3、需要设置一个类保存线程中的request、response、ServletContext、session对象信息,使用ThreadLocal类。

package cn.ren.util.web;import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;public class ServletObjectUtil {private static ThreadLocal<HttpServletRequest> requestThreadLocal = new ThreadLocal<HttpServletRequest>();private static ThreadLocal<HttpServletResponse> responseThreadLocal = new ThreadLocal<HttpServletResponse>() ;private ServletObjectUtil() {}public static void clear() {requestThreadLocal.remove();responseThreadLocal.remove();}public static void setRequest(HttpServletRequest request) {requestThreadLocal.set(request);}public static void setResponse(HttpServletResponse response) {responseThreadLocal.set(response);}public static HttpServletRequest getRequest() {return requestThreadLocal.get() ;}public static HttpServletResponse getResponse() {return responseThreadLocal.get() ;}public static HttpSession getSession() {return requestThreadLocal.get().getSession() ;}public static ServletContext getServletConText() {return requestThreadLocal.get().getServletContext() ;}}

6、在Dispacher处理的时候,应该将当前用户的请求交给ThreadLocal类对象处理,因为ModelAndView接收的url,EmpAction类负责跳转路径与业务操作方法的调用,都没有request、response对象,因此需要用ThreadLocal将request、response保存下来。

package cn.ren.servlet;import java.io.IOException;
import java.util.Arrays;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import cn.ren.util.web.ActionBeanUtil;
import cn.ren.util.web.ModelAndView;
import cn.ren.util.web.RequestUrlUtil;
import cn.ren.util.web.ServletObjectUtil;
/*** 项目的设计者需要把控制层的程序类编写完整,并使其功能足够强大* @author ren**/
@SuppressWarnings("serial")
public class DispatcherServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 所有的请求交给服务方法创建请求处理线程ServletObjectUtil.setRequest(request);ServletObjectUtil.setResponse(response);String uriResult [] = RequestUrlUtil.splitUrl(request) ;// DispatcherServlet只是负责数据的跳转操作try {ModelAndView mav = ActionBeanUtil.actionHandle(uriResult) ;if(mav != null) {request.getRequestDispatcher(mav.getUrl()).forward(request, response); }ServletObjectUtil.clear();} catch (Exception e) {e.printStackTrace();}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}

7、现在就意味着在Action类中就可以取得request与response对象信息

8、完善ModelAndView的程序类定义

package cn.ren.util.web;import java.util.Map;public class ModelAndView {private String url ;public ModelAndView(){}public ModelAndView(String url) {this.url = url ;}/*** 设置request属性* @param name* @param value*/public void add(String name,Object value) {ServletObjectUtil.getRequest().setAttribute(name, value);}/*** 将map中的内容转化在request中保存* @param map*/public void add(Map<String,Object> map) {for(Map.Entry<String, Object> me : map.entrySet()) {ServletObjectUtil.getRequest().setAttribute(me.getKey(), me.getValue());}}public void setUrl(String url) {this.url = url;}public String getUrl() {return url;}}

9、通过Action传递属性

package cn.ren.action;import java.util.ArrayList;
import java.util.List;import cn.ren.util.web.ModelAndView;
import cn.ren.util.web.ServletObjectUtil;
import cn.ren.vo.Dept;
/*** 开发者才会关注此处的程序类* @author ren**/
public class EmpAction {public EmpAction() {System.out.println("** EmpAction实例化 ");}public void show() throws Exception{ServletObjectUtil.getResponse().getWriter().println("ren");ServletObjectUtil.getResponse().getWriter().print(ServletObjectUtil.getRequest().getContextPath());}public ModelAndView addPre() { // 无参的操作ModelAndView mav = new ModelAndView("/pages/back/admin/emp/emp_add.jsp") ;List<Dept> all = new ArrayList<Dept>();for(int i = 0; i < 10; i++) {Dept vo = new Dept();vo.setDeptno(i);vo.setDname("ren" + i);vo.setLoc("shanghai" + i);all.add(vo) ;}mav.add("allDept",all);// 中间可能是你的一些业务的操作方法调用return mav ;}
}

现在的模型可以实现多业务处理,也可以实现属性传递处理

接收请求参数

在很多开发之中,接收参数是一件非常痛苦的事情,因为所有的参数接收都必须通过request.getParameter()进行接收,然后按照对应的类型进行转换处理,要想解决它就需要利用反射机制进行操作,本操作里面一定会使用到javassist的开发包。

接收基本数据类型

在实际开发中,经常使用到的数据类型:int\long\double\String\Date。假设所有提交的参数都是正确的参数格式。

1、定义emp_add.jsp页面

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<%String basePath = request.getScheme() + "://" + request.getServerName() + ":"+ request.getServerPort() + request.getContextPath() ;
%>
<%!public static final String EMP_ADD_URL = "pages/back/admin/EmAction!add.action" ;
%><base herf="<%=basePath%>"/>
<title>Insert title here</title>
</head>
<body><h1>雇员增加表单</h1><form action="<%= EMP_ADD_URL%>" method="post">雇员编号long : <input type="text" name="empno" value=10> <br>雇员姓名String : <input type="text" name="ename" value="smith"><br>雇员工资double : <input type="text" name="sal" value="100.00"><br>雇员年龄int: <input type="text" name="age" value="19"><br>雇佣日期Date : <input type="text" name="hiredate" value="2020-5-20"><br><input type="submit" value="注册"> <br></form> </body>
</html>

2、定义EmpAction.add()方法,该方法暂时不使用VO的形式接收;

 public String add(long empno,String ename,double sal,int age,Date hiredate) {System.out.println(empno + "、" + ename + "、" + sal + "、" + age + "、" + hiredate);return "/pages/back/admin/emp/EmpAction!addPre.action" ;}

3、根据参数名称取得参数内容,随后反射调用add()方法,需要改ActionBeanUtil的调用,如果现在发现参数,那么必须根据参数取得对应的数据。

反射调用方法对于可变参数由两种调用形式:method类对象.invoke(类的实例化对象,参数内容,参数内容,..) ; method类对象.invoke(类的实例化对象,Object参数内容[])

那么就意味着按照指定的参数名称将接收到的参数变为参数类型,随后将这些内容保存在Object数组里面。

4、应该准备一个专门进行数组操作的处理类,将方法中的参数名称与request.getParameter()结合一起使用,这个类只是返回要传递的参数内容。ParameterValueUtil。如果要进行参数的接收一定会涉及到参数类型的转换。对于参数有可能转变为各种参数类型,在ParameterValueUtil追加一个新的方法

package cn.ren.util.web;import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.ParseException;
import java.text.SimpleDateFormat;import javassist.ClassClassPath;
import javassist.ClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;/*** 专门进行javassist的反射参数取得以及进行通过参数取得对应的提交参数内容* @author ren**/
public class ParameterValueUtil {private ParameterValueUtil () {}/*** 进行指定参数内容的取得* @param paraName 参数名称* @paramType 参数的类型* @return 返回各自参数内容,并且根据指定参数类型进行转型* @throws Exception */public static Object getParameterValue(String paramName, String paramType) throws Exception {String val = ServletObjectUtil.getRequest().getParameter(paramName) ;if("int".equals(paramType) || "java.lang.Integer".equals(paramType)){if(val == null || "".equals(val)) {return 0 ;} else {return Integer.parseInt(val) ;}} else if("double".equals(paramType) || "java.lang.Double".equals(paramType)) {if(val == null || "".equals(val)) {return 0.0;}else {return Double.parseDouble(val) ;}} else if("long".equals(paramType) || "java.lang.Long".equals(paramType)) {if(val == null || "".equals(val)) {return 0 ;} else {return Long.parseLong(val) ;}} else if("java.util.Date".equals(paramType)) {if(val == null || "".equals(val)) {return null ;} else {String pattern = "yyyy-MM-dd" ;if(val.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) { // 日期时间pattern = "yyyy-MM-dd hh:mm:ss" ;} SimpleDateFormat sdf = new SimpleDateFormat(pattern) ;return sdf.parse(val) ;}} else if("String".equals(paramType) || "java.lang.String".equals(paramType)) {if(val == null || "".equals(val)) {return "" ;} else {return val ;}}return null;}/*** 进行方法的参数处理操作,将请求的参数的内容取出后变为对象数组返回* @param actionClass 触发此操作的Action程序类* @param actionMethod 触发此操作的方法* @return 所有参数对应的内容都会以对象数组的形式返回,如果某一个参数没有接收到按null处理;* @throws Exception */public static Object[] getMethodParameter(Class<?> actionClass,Method actionMethod) throws Exception {Class<?> params [] = actionMethod.getParameterTypes() ;  // 取得指定方法的参数信息ClassPool classPool = ClassPool.getDefault() ;// javassist开发包如果要进行类的加载操作,那么就需要ClassPath完成,如果在Tomcate中运行,这个ClassPath会被Tomcate干掉// 那么就必须自己来手工设置ClassPathClassPath classPath = new ClassClassPath(actionClass) ; // 将指定类型的Class类对象(ClassLoader)放入到ClassPath类中classPool.insertClassPath(classPath) ; // 明确的告诉Javassist开发要通过那个ClassPath加载程序类CtClass ctClass = classPool.get(actionClass.getName()) ; // 要操作类的字节码文件CtMethod ctMethod = ctClass.getDeclaredMethod(actionMethod.getName()) ;  // 取得要操作的方法对象MethodInfo methodInfo = ctMethod.getMethodInfo() ; // 取得方法的信息// 以上取得方法的相关信息项CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); // 获取代码的属性LocalVariableAttribute attribute = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag) ;  // 取得属性标签(名称)Object dataObj [] = new Object[params.length] ; // 返回数组内容int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1 ; // 要考虑方法中带有static标志的问题for(int i = 0; i < params.length; i ++) {String paramName = attribute.variableName(i + pos); //取得参数名称String paramType = params[i].getName() ; // 取得参数类型System.out.println(params[i]);dataObj[i] = getParameterValue(paramName, paramType) ; // 保存数据到数组里面}return dataObj ;}
}

参数与VO对象转换

对于基础的参数处理只需要按照接收类型转换即可,但是可能有VO类型等待用户接收处理。

1、定义表单传递混合参数

 <form action="<%= EMP_EDIT_URL%>" method="post">操作人员信息:<input type="text" name="mid" value="renjava" ><br>雇员编号long : <input type="text" name="empno" value=10> <br>雇员姓名String : <input type="text" name="ename" value="smith"><br>雇员工资double : <input type="text" name="sal" value="100.00"><br>雇员年龄int: <input type="text" name="age" value="19"><br>雇佣日期Date : <input type="text" name="hiredate" value="2020-5-20"><br><input type="submit" value="注册"> <br></form> 

2、在EmpAction里面追加新的方法:

package cn.ren.vo;
import java.io.Serializable;
import java.util.Date;
@SuppressWarnings("serial")
public class Emp implements Serializable {private Long empno ;private String ename ;private Double sal ;private Date hiredate ;private Integer age ;
}
 public String edit(String mid,Emp vo) {System.out.println("## mid = " + mid);System.out.println("## vo = " + vo);return null ;}

3、需要这针对VO类型的参数做一个处理,需要考虑对象的反射实例化的问题。既然属于参数内容的操作,应该在ParameterValueUtil中进行处理。

package cn.ren.util.web;import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;import cn.ren.util.StringUtil;
import javassist.ClassClassPath;
import javassist.ClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;/*** 专门进行javassist的反射参数取得以及进行通过参数取得对应的提交参数内容* @author ren**/
public class ParameterValueUtil {private ParameterValueUtil () {}/** * 根据传入的参数进行对象实例化的处理* @param voClass 参数类型依靠此类型进行反射对象实例化* @return 一个实例化好的vo类对象*/public static Object getObjectParameterValue(Class<?> voClass) throws Exception{Object voObject = voClass.getDeclaredConstructor().newInstance() ;   // 反射实例化vo类对象Field fields [] = voClass.getDeclaredFields() ; // 取得所有属性名称for (int i = 0;i < fields.length; i++) {Method method = voClass.getMethod("set" + StringUtil.initcap(fields[i].getName()),fields[i].getType()) ;method.invoke(voObject, getBasicParameterValue(fields[i].getName(),fields[i].getType().getName())) ; // 将值设置到里面}return voObject;}/*** 判断当前类型是简单类型还是vo类 * @param paramType 操作类型* @return*/public static boolean isBasic(String paramType) {return "int".equals(paramType) || "java.lang.Integer".equals(paramType)|| "double".equals(paramType) || "java.lang.Double".equals(paramType)|| "long".equals(paramType) || "java.lang.Long".equals(paramType) || "String".equals(paramType) || "java.lang.String".equals(paramType) || "java.util.Date".equals(paramType) ;}/*** 进行指定参数内容的取得* @param paraName 参数名称* @paramType 参数的类型* @return 返回各自参数内容,并且根据指定参数类型进行转型* @throws Exception */public static Object getBasicParameterValue(String paramName, String paramType) throws Exception {String val = ServletObjectUtil.getRequest().getParameter(paramName) ;if("int".equals(paramType) || "java.lang.Integer".equals(paramType)){if(val == null || "".equals(val)) {return 0 ;} else {return Integer.parseInt(val) ;}} else if("double".equals(paramType) || "java.lang.Double".equals(paramType)) {if(val == null || "".equals(val)) {return 0.0;}else {return Double.parseDouble(val) ;}} else if("long".equals(paramType) || "java.lang.Long".equals(paramType)) {if(val == null || "".equals(val)) {return 0 ;} else {return Long.parseLong(val) ;}} else if("java.util.Date".equals(paramType)) {if(val == null || "".equals(val)) {return null ;} else {String pattern = "yyyy-MM-dd" ;if(val.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) { // 日期时间pattern = "yyyy-MM-dd hh:mm:ss" ;} SimpleDateFormat sdf = new SimpleDateFormat(pattern) ;return sdf.parse(val) ;}} else if("String".equals(paramType) || "java.lang.String".equals(paramType)) {if(val == null || "".equals(val)) {return "" ;} else {return val ;}}return null;}/*** 进行方法的参数处理操作,将请求的参数的内容取出后变为对象数组返回* @param actionClass 触发此操作的Action程序类* @param actionMethod 触发此操作的方法* @return 所有参数对应的内容都会以对象数组的形式返回,如果某一个参数没有接收到按null处理;* @throws Exception */public static Object[] getMethodParameter(Class<?> actionClass,Method actionMethod) throws Exception {Class<?> params [] = actionMethod.getParameterTypes() ;  // 取得指定方法的参数信息ClassPool classPool = ClassPool.getDefault() ;// javassist开发包如果要进行类的加载操作,那么就需要ClassPath完成,如果在Tomcate中运行,这个ClassPath会被Tomcate干掉// 那么就必须自己来手工设置ClassPathClassPath classPath = new ClassClassPath(actionClass) ; // 将指定类型的Class类对象(ClassLoader)放入到ClassPath类中classPool.insertClassPath(classPath) ; // 明确的告诉Javassist开发要通过那个ClassPath加载程序类CtClass ctClass = classPool.get(actionClass.getName()) ; // 要操作类的字节码文件CtMethod ctMethod = ctClass.getDeclaredMethod(actionMethod.getName()) ;  // 取得要操作的方法对象MethodInfo methodInfo = ctMethod.getMethodInfo() ; // 取得方法的信息// 以上取得方法的相关信息项CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); // 获取代码的属性LocalVariableAttribute attribute = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag) ;  // 取得属性标签(名称)Object dataObj [] = new Object[params.length] ; // 返回数组内容int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1 ; // 要考虑方法中带有static标志的问题for(int i = 0; i < params.length; i ++) {String paramName = attribute.variableName(i + pos); //取得参数名称String paramType = params[i].getName() ; // 取得参数类型if(isBasic(paramType)) {dataObj[i] = getBasicParameterValue(paramName, paramType) ; // 保存数据到数组里面} else {dataObj[i] = getObjectParameterValue(params[i]) ;}  }return dataObj ;}
}

接收数组参数

如果要进行删除处理,往往需要接收一组的id数据,那么这个时候可以接收的内容往往都会是一个数组,不要在接收的参数上搞Set集合。

1、在EmpAction程序类上定义一个删除操作,

 public String delet1(String ids[]) {System.out.println("## delet1" + Arrays.toString(ids));return null ;}public String delet2(int ids[]) {System.out.println("## delet1" + Arrays.toString(ids));return null ;}

2、对于数组类型的参数取得,需要追加一个判断参数的接收类型是否是数组的处理,

 /*** 判断方法上的参数是否是一个数组类型* @param paramType* @return*/public static boolean isArray(String paramType) {return "int[]".equals(paramType) || "String[]".equals(paramType) ;}
 /** * 进行数组的操作处理,可以处理组合的字符串以及复选框提交* @param paramName* @param paramType* @return*/public static Object getArrayParamemterValue(String paramName, String paramType) {String val = ServletObjectUtil.getRequest().getParameter(paramName) ;  // 取得参数内容       if(val.contains(",")) { // 如果有",",需要拆分处理,只接收一次数据即可String result [] = val.split(",") ; // 按照”,“拆开if("int[]".equals(paramType) || "Integer[]".equals(paramType)) {  // 整型数组int data[] = new int [result.length] ;for(int i = 0; i < data.length; i ++) {data[i] = Integer.parseInt(result[i]) ;}return data ;}return result ; // 字符串直接返回}else { // 提交的是一个复选框String result [] = ServletObjectUtil.getRequest().getParameterValues(paramName) ;if("int[]".equals(paramType) || "Integer[]".equals(paramType)) {  // 整型数组int data[] = new int [result.length] ;for(int i = 0; i < data.length; i ++) {data[i] = Integer.parseInt(result[i]) ;}return data ;}return result;}}

http://localhost/MyDispatcherServlet/pages/back/admin/emp/EmpAction!delet1.action?ids=1&ids=2

http://localhost/MyDispatcherServlet/pages/back/admin/emp/EmpAction!delet2.action?ids=1,2,3,4,5

这些设计是属于针对于我们自己的项目的设计提高。

表单封装问题

在实际开发之中会存在有表单封装问题,而一旦出现表单封装,request对象可能会失效的问题。表单封装:

<form action="<%= EMP_ADD_URL%>" method="post" enctyple="multipart/form-data"></form>

判断表单进行封装

范例:在DispatcherServlet程序类里面追加一个判断用户请求类型的操作

System.out.println("***" + request.getContentType());

表单封装,返回信息:

multipart/form-data; boundary=---------------------------7e439d7306f4

表单没有封装,返回信息:

application/x-www-form-urlencoded

如果发现表单进行封装了,那么就必须使用SmartUpload进行参数的接收处理

     String requestContentType = request.getContentType() ; // 取得当前表单模式if(requestContentType.contains("multipart/form-data")) { // 表单封装}

接收参数处理

现在既然已经区分出了程序的提交参数,那么就需要解决参数内容的取得。根据提交的ContentType不同,则取得的模式也不同。

1、既然表单要进行封装处理,意味着程序要考虑文件上传问题。

2、扩充ServletObjectUtil类的方法,追加SmartUpload类对象的保存;

private static ThreadLocal<SmartUpload> smartThreadLocal = new ThreadLocal<SmartUpload>() ;
 public static void clear() {requestThreadLocal.remove();responseThreadLocal.remove();smartThreadLocal.remove();}public static void setSmartUpload(SmartUpload smart) {smartThreadLocal.set(smart);}public static SmartUpload getSmartUpload() {return smartThreadLocal.get();}

3、在DisptacherServlet类中就需要将SmartUpload对象传递到ServletObjectUtil类中

     String requestContentType = request.getContentType() ; // 取得当前表单模式if(requestContentType.contains("multipart/form-data")) { // 表单封装// 表单一旦被封装就有可能进行文件的上传处理,就要准备好SmartUpload组件,但是这个组件最终还是交给各个的Action去操作SmartUpload smart = new SmartUpload() ;smart.initialize(super.getServletConfig(), request, response);try {smart.upload();} catch (ServletException | IOException | SmartUploadException e) {e.printStackTrace();}ServletObjectUtil.setSmartUpload(smart);}

4、随后解决参数的接收问题,所有参数需要根据请求类型进行判断。

/*** 取得指定的参数,不管表单是否封装了,除非没有传递参数* @param param* @return*/public static String getParameter(String param) {if(ServletObjectUtil.getRequest().getContentType().contains("multipart/form-data")) { // 表单封装return ServletObjectUtil.getSmartUpload().getRequest().getParameter(param) ;} else {return ServletObjectUtil.getRequest().getParameter(param) ;}}/*** 取得请求的一组参数* @param param* @return*/   public static String[] getParameterValues(String param) {if(ServletObjectUtil.getRequest().getContentType().contains("multipart/form-data")) { // 表单封装return ServletObjectUtil.getSmartUpload().getRequest().getParameterValues(param) ;} else {return ServletObjectUtil.getRequest().getParameterValues(param) ;}}

之后更。。。。。。。

MVC设计模式,自己搭建MVC开发框架相关推荐

  1. php的mvc设计模式,什么是MVC设计模式?,

    详细内容 Model View Controller简称MVC,即模型视图控制器.MVC设计模式指定应用程序由数据模型.呈现信息和控制信息组成.该模式要求将每个模式分成不同的对象. MVC更像是一种架 ...

  2. MVC设计模式及Sprint MVC设计模式

    文章目录 一.MVC设计模式简介 二.Spring MVC处理用户请求的完整流程 2.1. Spring MVC 框架主要由 DispatcherServlet.处理器映射.控制器.视图解析器.视图组 ...

  3. iOS——MVC设计模式

    什么是MVC MVC是Model-View-Controller的简写,它表示的是一种常见的客户端软件开发框架.可见他是由三个部分组成的. 下面解释一下这三个部分: Model:即为模型,用来存储业务 ...

  4. jsp 将页面中的值导入java中_JavaWeb - JSP:概述和语法,内置对象,JavaBean 组件,MVC 设计模式

    JSP 的概述 概念 JSP 是 Java Server Pages 的简称,跟 Servlet 一样可以动态生成 HTML 响应, JSP 文件命名为 xxx.jsp. 与 Servlet 不同,J ...

  5. JavaBean、MVC设计模式与Java中Dao、Service、Controll三层体系

    文章目录 一.JavaBean JavaBean实际就是一个普通的Java类,为了规范开发,要求JavaBean具有如下规范: ① 具有一个公共的.无参的构造方法: ② 类的属性私有,且必须提供公共的 ...

  6. Java MVC设计模式

    前言  MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范,用一种业务逻辑.数据.界面显示分离的方 ...

  7. MVC设计模式与JavaWeb的三层架构

    引言: MVC是一种设计思想,是无色无味看不见摸不着的.它是设计师脑子里的东西,而web的三层架构则是落地实现,也就是划分各部分的包(controller.service.dao),然后进行代码的编写 ...

  8. 第80节:Java中的MVC设计模式

    第80节:Java中的MVC设计模式 前言 了解java中的mvc模式.复习以及回顾! 事务,设置自动连接提交关闭. setAutoCommit(false); conn.commit(); conn ...

  9. Xamarin简介与Xamarin支持MVC设计模式

    Create Native iOS, Android, Mac and Windows apps in C#. 官方网站:http://xamarin.com/ 使用武器 Run a C# app, ...

最新文章

  1. keras中重要的函数用法及参数详解
  2. 购物篮推荐场景太复杂?没有商品相关性标签?看作者运用对比学习统统解决...
  3. Win10系列:VC++ Direct3D模板介绍1
  4. Excel的基础操作
  5. 永远要跟比你更成功的人在一起
  6. LeetCode 2035. 将数组分成两个数组并最小化数组和的差(状态压缩DP)
  7. 爱奇艺的测试工程师笔试题
  8. 1198. Jobbery
  9. java设计模式—单例模式
  10. 捕获事件要比冒泡事件先触发
  11. 商淘软件S2B2C供应链系统 支持多种电商模式
  12. IBM InfoSphere Optim数据增长解决方案:在Optim归档文件上启用安全性
  13. TP5用PHPMailer发送邮件
  14. ios开发调用系统相机(照片/视频)
  15. 分数换算小数补0法_小学数学概念+知识点顺口溜汇总+常用单位换算汇总
  16. 这个 Go 开发的网络抓包工具,不仅好用还支持ES检索
  17. Samba服务器配置和使用全过程
  18. qq客服不需要加好友的html方法
  19. html5屏蔽技术,实用javaScript屏蔽技术
  20. Git三大特色之WorkFlow(工作流)

热门文章

  1. I won't tell you this is about graph theory----zjfc bellman-ford算法与spfa算法
  2. 折腾StatusNet(原laconica),搭建个人微博平台
  3. oracle erp和金蝶,ERP和金蝶软件有什么区别!
  4. 供应链厂商信息-2014
  5. Redis实现短信登入功能(一)传统的Session登入
  6. python的增添删除查询列表
  7. FPGA IP核 串口实验 signaltap
  8. 小白学数据 | 除了计算大姨妈周期,时间序列分析还有什么用
  9. ubuntu使用sudo su进入root报错Cannot execute /bin/csh: No such file or directory解决方法
  10. 小灵通听证?这些律师是不识字还是不懂法?