框架结构说明
框架采用MVC模式,Ioc控制反转技术。通过框架来对应用进行初始化和管理,提高开发效率。
若使用传统的Servlet来开发Java Web,Servlet的数量会随着业务功能的扩展而不断增加,系统变得庞大,然以维护,有必要减少Servlet数量,
将某类业务交给Controller来处理,Service负责给Controller提供服务。Service不是通过new方式来创建的,而是通过"依赖注入"的方式,由框架来创建所需要的对象。
框架结构图:
DispatherServlet: 请求转发器,通过service()方法转发所有的请求。
Loader: 在DispatherServlet的init()方法调用,进行应用的初始化工作。
ClassHelper:通过ClassUtil类加载应用基础包下所有的类。
BeanContainer:通过BeanFactory将ClassHelper加载获取的所有带有Controller,Service注解等需要容器管理的类进行实例化并保存在容器中。
IocHelper:Controller中定义Service成员变量,需要通过框架自身来实例化。IocHelper将Controller中定义 Service成员变量进行依赖注入。
ControllerHelper:将Controller中带有RequestMapping注解的方法与其要处理的请求路径和请求方法建立映射关系。
创建Maven Web工程 framework-diy,在pom.xml文件引入需要的包。servlet-api,jsp-api,jstl,commons-lang3,commons-collections4,jackson等。
javax.servlet
javax.servlet-api
3.0.1
javax.servlet.jsp
jsp-api
2.2
javax.servlet
jstl
1.2
org.apache.commons
commons-lang3
3.3.2
org.apache.commons
commons-collections4
4.0
com.fasterxml.jackson.core
jackson-databind
2.4.5
加载配置项
首先我们来看下Spring框架,Spring框架定义了一个spring-config.xml配置文件,可以在配置文件定义基础包名,JSP基础路径,静态资源文件的路径等等。
现在我们来仿造一下,为框架定义一个简单的配置文件config.properties(默认配置文件为config.properties),放在/src/main/resources目录下。框架需要根据这些配置项来初始化应用。
//config.properties
#基础包名
app.base_package = com.hubwiz.web
#jsp路径
app.jsp_path = /jsp/
#静态资源路径
app.asset_path = /asset/
有了配置文件,我们需要编写一个PropsUtil类来加载配置文件config.properties。获取当前线程的类加载器,getContextClassLoader().getResourceAsStream(fileName)根据文件名称来加载配置文件。
//加载配置文件
public classPropsUtil {/*** 加载配置文件
*
*@paramfileName 配置文件名
*@return
*/
public staticProperties loadProps(String fileName) {
Properties props= null;
InputStream is= null;try{
is=Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);if (is == null) {throw new FileNotFoundException(fileName + " file is not found");
}
props= newProperties();
props.load(is);
}catch(IOException ioe) {
ioe.printStackTrace();
}finally{if (is != null) {try{
is.close();
}catch(IOException ioe) {
ioe.printStackTrace();
}
}
}returnprops;
}/*** 获取字符型属性(默认值为空字符串)
*
*@paramprops
*@paramkey
*@return
*/
public staticString getString(Properties props, String key) {return getString(props, key, "");
}/*** 获取字符型属性(可指定默认值)
*
*@paramprops
*@paramkey
*@paramdefaultValue
*@return
*/
public staticString getString(Properties props, String key, String defaultValue) {
String value=defaultValue;if(props.containsKey(key)) {
value=props.getProperty(key);
}returnvalue;
}
}
获取配置文件属性
加载了配置文件,需要编写一个类ConfigHelper来获取配置文件属性。框架初始化需要根据配置文件来初始化应用。框架默认配置文件为config.properties,只有创建了名为config.properties的配置文件,框架才能运行。
/*** 获取配置文件属性*/
public classConfigHelper {private static final Properties CONFIG_PROPS = PropsUtil.loadProps("config.properties");//默认配置文件为config.properties
/*** 获取应用基础包名
*
*@return
*/
public staticString getAppBasePackage() {returnPropsUtil.getString(CONFIG_PROPS, Constant.APP_BASE_PACKAGE);
}/*** 获取JSP路径
*
*@return
*/
public staticString getAppJspPath() {returnPropsUtil.getString(CONFIG_PROPS, Constant.APP_JSP_PACKAGE);
}/*** 获取应用静态资源路径
*
*@return
*/
public staticString getAppAssetPath() {return PropsUtil.getString(CONFIG_PROPS, Constant.APP_ASSET_PATH, "/asset/");
}
}
类加载器
实现一个类加载器ClassUtil来加载基础包下的所有的类。只有加载了这些类,框架才能对其进行初始化。获取当前线程的ClassLoader通过这个类加载器来加载类,获取指定包名下的所有的类,需要指定根据包名并将其转换为文件路径,读取class文件或jar包,获取指定的类名去加载类。
/*** 获取类加载器
*
*@return
*/
public staticClassLoader getClassLoader() {returnThread.currentThread().getContextClassLoader();
}/*** 加载类
*
*@paramclassName 类名称
*@paramisInitialized 是否执行类的静态代码块
*@return
*/
public static Class> loadClass(String className, booleanisInitialized) {
Class>clazz;try{
clazz=Class.forName(className, isInitialized, getClassLoader());
}catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();throw newRuntimeException(cnfe);
}returnclazz;
}/*** 获取指定包下所有类
*
*@parampackageName
*@return
*/
public static ArrayList>getClasses(String packageName) {
ArrayList> classes = new ArrayList<>();try{
Enumeration urls = getClassLoader().getResources(packageName.replace(".", "/"));while(urls.hasMoreElements()) {
URL url=urls.nextElement();if (url != null) {
String protocol=url.getProtocol();if (protocol.equals("file")) {
String packagePath= url.getPath().replaceAll("%20", " ");
addClass(classes, packagePath, packageName);
}else if (protocol.equals("jar")) {
JarURLConnection jarURLConnection=(JarURLConnection) url.openConnection();if (jarURLConnection != null) {
JarFile jarFile=jarURLConnection.getJarFile();if (jarFile != null) {
Enumeration jarEntries =jarFile.entries();while(jarEntries.hasMoreElements()) {
JarEntry jarEntry=jarEntries.nextElement();
String jarEntryName=jarEntry.getName();if (jarEntryName.equals(".class")) {
String className= jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
doAddClass(classes, className);
}
}
}
}
}
}
}
}catch(Exception e) {
e.printStackTrace();throw newRuntimeException(e);
}returnclasses;
}
...
...
...
}
定义注解
本框架采用注解来标识Controller,Service类。所以需要定义注解来标识那些类是Controller,Controller类中那些方法响应url请求等。
控制器类上使用Controller注解,在控制器类的方法上使用RequestMapping注解,使用Autowired注解将服务类依赖注入进来。服务类使用Service注解。
/*** 控制器注解*/@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)public @interfaceController {
}/*** 请求方法注解*/@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)public @interfaceRequestMapping {//请求类型路径
String path();//请求方法
String method();
}/*** 服务类注解*/@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)public @interfaceService {
}/*** 依赖注入注解*/@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)public @interfaceAutowired {
}
获取类
Controller,Service类是框架需要管理的类,把他们统称为Bean类。实现一个类可以获取应用所有的Controller,Service类。首先调用ConfigHelper.getAppBasePackage()获取基础包名,然后调用ClassUtil.getClasses(basePackage)加载该基础包名下所有的类,保存在变量ArrayList> classes中;再遍历ArrayList> classes获取Controller,Service等类。
//获取类
public classClassHelper {//基础包名下所有的类
private static final ArrayList>classes;static{
String basePackage=ConfigHelper.getAppBasePackage();
classes=ClassUtil.getClasses(basePackage);
}/*** 获取基础包名下所有的类
*
*@return
*/
public static ArrayList>getClasses() {returnclasses;
}/*** 获取所有Service类
*
*@return
*/
public static ArrayList>getServiceClasses() {
ArrayList> sc = new ArrayList<>();//补全代码
returnsc;
}/*** 获取所有Controller类
*
*@return
*/
public static ArrayList>getControllerClasses() {
ArrayList> cc = new ArrayList<>();for (Class>c : classes) {if (c.isAnnotationPresent(Controller.class)) {
cc.add(c);
}
}returncc;
}/*** 框架Bean容器主要管理Service,Controller类
*
*@return
*/
public static ArrayList>getBeanClasses() {
ArrayList> bc = new ArrayList<>();
bc.addAll(getServiceClasses());
bc.addAll(getControllerClasses());returnbc;
}
}
现在来测试类加载器和获取类是否正确,配置文件将基础包名设为app.base_package=com.hubwiz.web.controller,在这个包下,实现了三个类HomeController类(带Controller注解),PersonService类(带Service注解),Person类。public static voidmain(String[] args) {
ArrayList> ces =ClassHelper.getClasses();for (Class>c : ces) {
System.out.println(c.getSimpleName());
}
}
Bean工厂
回顾下前面的知识,通过加载配置文件获取应用基础包名,加载基础包名下所有的类,获取Controller,Service类。到目前为止,我们只是加载了类,但是无法通过获取的类来实例化对象。因此需要一个反射工具,来实例化类。
创建一个Bena工厂,来生产(实例化Bean类对象)Bean。newInstance()方法,实例化目标类;invokeMethod()通过反射机制来调用类中的方法;setField()通过反射机制为类成员遍历赋值。
//Bean工厂
public classBeanFactory {/*** 创建实例
*
*@paramclazz
*@return
*/
public static Object newInstance(Class>clazz) {
Object instance;try{
instance=clazz.newInstance();
}catch(Exception e) {throw newRuntimeException(e);
}returninstance;
}/*** 方法调用
*
*@paramobj
*@parammethod
*@paramargs
*@return
*/
public staticObject invokeMethod(Object obj, Method method, Object... args) {
Object result;try{
method.setAccessible(true);
result=method.invoke(obj, args);
}catch(Exception e) {throw newRuntimeException(e);
}returnresult;
}/*** 设置成员变量值
*
*@paramobj
*@paramfield
*@paramvalue*/
public static voidsetField(Object obj, Field field, Object value) {try{
field.setAccessible(true);
field.set(obj, value);
}catch(Exception e) {throw newRuntimeException(e);
}
}
}
Bean容器
前面在ClassHelper定义了方法getBeanClasses()来获取Bean容器需要管理的所有Controller,Service类,获取这些类以后,调用BeanFactory.newInstance(Class clazz)方法来实例化类的对象,缓存在Map beanContainer中,需要随时获取。Map说明:使用类全名称作为key,类的实例对象作为value值。
BeanContainer初始化:首先调用ClassHelper.getBeanClasses()获取所有的Bean类,调用Bean工厂方法newInstance()方法来实例化Bean类,保存在beanContainer中。通过类全名称从beanContainer获取需要的Bean实例对象。
/*** Bean容器*/
public classBeanContainer {/*** 存放Bean类名称和Bean实例的映射关系*/
private static final Map beanContainer = new HashMap<>();static{
ArrayList> beanClasses =ClassHelper.getBeanClasses();for (Class>beanClass : beanClasses) {
Object obj=BeanFactory.newInstance(beanClass);
beanContainer.put(beanClass.getName(), obj);
}
}/*** 获取Bean映射
*
*@return
*/
public static MapgetBeanContainer() {returnbeanContainer;
}/*** 获取Bean实例*/
public static T getBean(String className) {if (!beanContainer.containsKey(className)) {throw new RuntimeException("can not get bean by className: " +className);
}return(T) beanContainer.get(className);
}/*** 设置Bean实例*/
public static voidsetBean(String className, Object obj) {//补全代码
}
}
依赖注入
首先来了解下Spring框架的核心机制:依赖注入。当某个Java实例(调用者)需要另一个Java实例(被调用者)时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。在依赖注入模式下,创建调用者的工作不再由调用者来完成,因此称为控制反转(Ioc);创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也成为依赖注入(DI)。
Controller中定义Service成员变量,需要通过框架自身来实例化。
首先通过beanContainer获取所有的Bean类全名称和Bean实例,遍历获取所有的Controller类,通过反射获取类中的成员变量,遍历这些成员变量看是否有Autowired注解,若有,从beanContainer中获取Bean实例,然后调用Bean工厂setField()方法将获取的Bean实例赋值给成员变量。
/*** 依赖注入*/
public final classIocHelper {static{
Map beanContainer =BeanContainer.getBeanContainer();if(CollectionUtil.isNotEmpty(beanContainer)) {
initIOC(beanContainer);
}
}private static void initIOC( MapbeanContainer) {for (Map.EntrybeanEntry : beanContainer.entrySet()) {
String className=beanEntry.getKey();
Object beanInstance=beanEntry.getValue();
Class> beanClass = null;try{
beanClass=Class.forName(className);
System.out.println(className);
}catch(ClassNotFoundException e) {
e.printStackTrace();
}//Controller类中定义的属性
Field[] beanFields =beanClass.getDeclaredFields();if(ArrayUtil.isNotEmpty(beanFields)) {for(Field beanField : beanFields) {//带有Autowired注解的成员变量
if (beanField.isAnnotationPresent(Autowired.class)) {//成员变量的类
Class> beanFieldClass =beanField.getType();
Object beanFieldInstance=beanContainer.get(beanFieldClass.getName());if (beanFieldInstance != null) {//依赖注入
BeanFactory.setField(beanInstance, beanField, beanFieldInstance);
}
}
}
}
}
}
}
Request
Controller类中带有RequestMapping注解的方法处理特定URL请求,如何判断当前请求 URL&Method 对应那个Controller & method,这是接下来要实现的。通过反射可以获取Controller中带有RequestMapping注解的方法,进而获得RequestMapping注解中请求方法和请求路径。封装一个请求对象request与处理request对象handler,将request与handler建立一个映射关系。
请求对象request:包括请求路径path;请求方法method两个属性。
处理request对象handler:包括Controller类;带有RequestMapping注解的方法method。
/*** 封装请求信息*/
public classRequest {//请求方法
privateString requestMethod;//请求路径
privateString requestPath;publicRequest(String requestMethod,String requestPath) {this.requestMethod =requestMethod;this.requestPath =requestPath;
}publicString getRequestMethod() {returnrequestMethod;
}publicString getRequestPath() {returnrequestPath;
}
@Overridepublic inthashCode() {return HashCodeBuilder.reflectionHashCode(this);
}
@Overridepublic booleanequals(Object obj) {return EqualsBuilder.reflectionEquals(this,obj);
}
}/*** 处理Request请求对应Controller & method*/
public classHandler {private Class>controllerClass;privateMethod method;public Handler(Class>controllerClass,Method method) {this.controllerClass =controllerClass;this.method =method;
}public Class>getControllerClass() {returncontrollerClass;
}publicMethod getMethod() {returnmethod;
}
}
RequestMapping
编写一个类ControllerHelper,将Controller类中定义处理Requet的方法,与Handler绑定。通过请求路径与请求方法我们能方便找到处理这个请求的Controller类和method。
public classControllerHelper {//请求request与处理请求handler映射关系
private static final Map RequestMap = new HashMap<>();static{
ArrayList> controllerClasses =ClassHelper.getControllerClasses();if(CollectionUtil.isNotEmpty(controllerClasses)) {
initRequestMapp(controllerClasses);
}
}private static void initRequestMapp(ArrayList>controllerClasses) {for (Class>controllerClass : controllerClasses) {
Method[] methods=controllerClass.getDeclaredMethods();if(ArrayUtil.isNotEmpty(methods)) {for(Method method : methods) {//带有RequestMapping注解的方法
if (method.isAnnotationPresent(RequestMapping.class)) {
RequestMapping rm= method.getAnnotation(RequestMapping.class);//请求路径与请求方法
Request request = newRequest(rm.method(), rm.path());//对应请求路径与请求方法的Controller和method
Handler handler = newHandler(controllerClass, method);
RequestMap.put(request, handler);
}
}
}
}
}/*** 获取handler
*
*@paramrequestMethod
*@paramrequestPath
*@return
*/
public staticHandler getHandler(String requestMethod, String requestPath) {
Request request= newRequest(requestMethod, requestPath);returnRequestMap.get(request);
}
}
初始化类
框架基本搭建起来了,现在需要编写一个类来初始化应用。
初始化步骤:
1、加载ClassHelper类,通过这个类加载基础包名下所有的类。
2、加载BeanContainer类,将基础包名下所有Bean类,通过Bean工厂实例化保存在Bean容器。
3、加载IocHelper类,实例化Bean类,需要为Controller类中带有Autowired注解的属性赋值。
4、加载ControllerHelper类,将Controller类中带有RequestMapping注解的方法,建立与请求路径和请求方法的映射关系,这样框架才能找到处理请求对应的方法。
/*** 初始化框架*/
public classLoader {public static voidinit() {
Class>[] cs = {ClassHelper.class,
BeanContainer.class,
IocHelper.class,
ControllerHelper.class};for (Class>c: cs) {
ClassUtil.loadClass(c.getName(),true);
}
}
}
请求参数
通常前端通过form表格的形式向后台发送数据,需要一个类封装从HttpServletRequest请求对象中获取所有的参数,然后传递给处理方法。首先解析请求参数(form表单数据),将其封装成Param类中,传递给Controller的方法处理。
通过request.getParameterNames()将发送请求页面中form表单所具有name属性的表单对象获取,request.getParameterValues(name)获取其值,生成FormParam保存在Param中。
/*** 解析请求参数,form表单数据*/
public classParameterUtil {public static Param createParam(HttpServletRequest request) throwsIOException {return newParam(parseParameterNames(request));
}private static MapparseParameterNames(HttpServletRequest request) {
Map formParams = new HashMap<>();//将发送请求页面中form表单所具有name属性的表单对象获取
Enumeration paramNames =request.getParameterNames();while(paramNames.hasMoreElements()) {
String fieldName=paramNames.nextElement();
String[] fieldValues=request.getParameterValues(fieldName);if(ArrayUtil.isNotEmpty(fieldValues)) {
Object fieldValue;if (fieldValues.length == 1) {
fieldValue= fieldValues[0];
}else{
StringBuilder sb= new StringBuilder("");for (int i = 0; i < fieldValues.length; ++i) {
sb.append(fieldValues[i]);if (i != fieldValues.length - 1) {
sb.append(StringUtil.separator);
}
}
fieldValue=sb.toString();
}
formParams.put(fieldName,fieldValue);
}
}returnformParams;
}
}
Param请求参数对象,封装了前端提交的form表格数据。
/*** 请求参数对象*/
public classParam {private MapformParams;public Param(MapformParams) {this.formParams =formParams;
}/*** 判断参数是否为空
*
*@returnboolean*/
public booleanisEmpty() {returnCollectionUtil.isEmpty(formParams);
}public MapgetFormParams() {returnformParams;
}/*** 根据参数名取String型参数值
*
*@paramname
*@return
*/
publicString getString(String name) {returnCastUtil.castString(formParams.get(name));
}public doublegetDouble(String name) {returnCastUtil.castDouble(formParams.get(name));
}public longgetLong(String name) {returnCastUtil.castLong(formParams.get(name));
}public intgetInt(String name) {returnCastUtil.castInt(formParams.get(name));
}publicBoolean getBoolean(String name) {returnCastUtil.castBoolean(formParams.get(name));
}
}
模型数据与视图
在处理请求时,通常会返回视图JSP页面和数据。所以现在需要将视图JSP路径和数据封装在一起返回。如果只返回数据,则返回JSON格式数据。
返回视图JSP,视图中包含视图JSP路径和视图中所需的数据:
public classModelAndView {//返回JSP路径
privateString path;//模型数据
private MapmData;publicModelAndView(String path) {this.path =path;
mData= new HashMap<>();
}publicModelAndView addmData(String key, Object obj) {
mData.put(key,obj);return this;
}publicString getPath() {returnpath;
}public MapgetmData() {returnmData;
}
}
返回数据,框架将其写入HttpServletRespone对象中,输出到客户端浏览器。
/*** 返回数据*/
public class Data{privateT datas;publicData(T datas) {this.datas =datas;
}publicT getDatas() {returndatas;
}
}
数据格式转换
由于返回的数据格式为JSON,现在需要将POJO转换成JSON格式。采用Jackson框架。
/*** POJO转换为JSON*/
public classJsonUtil {/*** 将POJO转化为JSON
*
*@paramobj
*@param
*@return
*/
public static String toJSON(T obj) {
String json= null;try{
ObjectMapper mapper= newObjectMapper();
json=mapper.writeValueAsString(obj);
}catch(Exception e) {
e.printStackTrace();
}returnjson;
}/*** 将JSON转化为POJO
*
*@paramjson
*@paramclazz
*@param
*@return
*/
public static T fromJSON(String json, Classclazz) {
T pojo= null;try{
ObjectMapper mapper= newObjectMapper();
pojo=mapper.readValue(json, clazz);
}catch(Exception e) {
e.printStackTrace();
}returnpojo;
}
}
请求转发器
请求转发器是框架的核心。请求转发器转发器用来处理所有的请求。DispatherServlet继承HttpServlet,在init()方法调用Loader.init()来初始化框架和应用。service()方法响应所有的请求。
请求转发过程:
1、通过req.getMethod().toLowerCase()获取请求方法(get,post,put delete);req.getContextPath()获取请求路径,根据请求路径和请求方法调用ControllerHelper.getHandler()方法获取处理这个请求对应的handler。
2、Hanler封装处理请求的Controller和方法,所有获取的handler,就可以获取处理请求的Controller和方法method。
3、获取了处理这个请求的Controller类,现在需要在Bean获取这个Controller类的实例对象,调用BeanContainer.getBean()来获取Controller类的实例对象。
4、调用ParameterUtil.createParam(req)来解析请求参数。
5、调用handler.getMethod()获取处理这个请求的方法,通过反射机制BeanFactory.invokeMethod()来调用这个方法,处理这个请求的方法就会来处理这个请求。
6、根据返回的结果是ModelAndView还是Data来处理返回问题。返回结果为ModelAndView,调用req.getRequestDispatcher(ConfigHelper.getAppJspPath() + path).forward(req, resp)将页面响应转发到ConfigHelper.getAppJspPath() + path;返回结果为Data,将返回结果POJO转换为JSON格式,写入HttpServletRespone对象中,输出到客户端浏览器。
/*** 请求转发器*/@WebServlet(urlPatterns= "/",loadOnStartup = 0)public class DispatherServlet extendsHttpServlet {
@Overridepublic void init(ServletConfig config) throwsServletException {
Loader.init();//初始化框架&应用
ServletContext sc =config.getServletContext();//注册JSP的Servlet
ServletRegistration jspServlet = sc.getServletRegistration("jsp");
jspServlet.addMapping(ConfigHelper.getAppJspPath()+ "*");//注册处理静态资源的Servlet
ServletRegistration defaultServlet = sc.getServletRegistration("default");
defaultServlet.addMapping(ConfigHelper.getAppAssetPath()+ "*");
}
@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException {//获取请求方法
String requestMethod =req.getMethod().toLowerCase();//请求路径url
String url =req.getRequestURI();
String contextPath=req.getContextPath();
String requestPath= null;if (contextPath != null && contextPath.length() > 0) {
requestPath=url.substring(contextPath.length());
}//获取处理这个请求的handler
Handler handler =ControllerHelper.getHandler(requestMethod, requestPath);//System.out.println(requestMethod + " " + requestPath);
if (handler != null) {
Class> controllerClass =handler.getControllerClass();
Object controllerBean=BeanContainer.getBean(controllerClass.getName());//解析请求参数
Param param =ParameterUtil.createParam(req);
Object result;//请求返回对象
Method method = handler.getMethod();//处理请求的方法
if(param.isEmpty()) {
result=BeanFactory.invokeMethod(controllerBean, method);
}else{
result=BeanFactory.invokeMethod(controllerBean, method, param);
}if (result instanceofModelAndView) {
handleViewResult((ModelAndView) result, req, resp);
}else{
handleDataResult((Data) result, resp);
}
}
}//返回为JSP页面
private static voidhandleViewResult(ModelAndView view, HttpServletRequest req, HttpServletResponse resp)throwsIOException, ServletException {
String path=view.getPath();if(StringUtil.isNotEmpty(path)) {if (path.startsWith("/")) {
resp.sendRedirect(req.getContextPath()+path);
}else{
Map data =view.getmData();for (Map.Entryentry : data.entrySet()) {
req.setAttribute(entry.getKey(), entry.getValue());
}//forward将页面响应转发到ConfigHelper.getAppJspPath() + path//补全代码
}
}
}//返回JSON数据
private static voidhandleDataResult(Data data, HttpServletResponse resp)throwsIOException {
Object model=data.getData();if (model != null) {
resp.setContentType("application/json");
resp.setCharacterEncoding("UTF-8");
PrintWriter writer=resp.getWriter();
String json=JsonUtil.toJSON(model);
writer.write(json);
writer.flush();
writer.close();
}
}
}
---汇智网