javaweb开发框架实例_javaweb框架

javaweb开发框架实例_javaweb框架

2023年7月29日发(作者:)

javaweb开发框架实例_javaweb框架框架结构说明框架采⽤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,在⽂件引⼊需要的包。servlet-api,jsp-api,jstl,commons-lang3,commons-collections4,jackson等。ckson-databind2.4.5加载配置项⾸先我们来看下Spring框架,Spring框架定义了⼀个配置⽂件,可以在配置⽂件定义基础包名,JSP基础路径,静态资源⽂件的路径等等。现在我们来仿造⼀下,为框架定义⼀个简单的配置⽂件ties(默认配置⽂件为ties),放在/src/main/resources⽬录下。框架需要根据这些配置项来初始化应⽤。//ties#基础包名_package = #jsp路径_path = /jsp/#静态资源路径_path = /asset/有了配置⽂件,我们需要编写⼀个PropsUtil类来加载配置⽂件ties。获取当前线程的类加载器,getContextClassLoader().getResourceAsStream(fileName)根据⽂件名称来加载配置⽂件。//加载配置⽂件public classPropsUtil {/*** 加载配置⽂件**@paramfileName 配置⽂件名*@return*/public staticProperties loadProps(String fileName) {Properties props= null;InputStream is= null;try{is=tThread().getContextClassLoader().getResourceAsStream(fileName);if (is == null) {throw newFileNotFoundException(fileName + " file is not found");}props= newProperties();(is);}catch(IOException ioe) {tackTrace();}finally{if (is != null) {try{();}catch(IOException ioe) {tackTrace();}}}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(nsKey(key)) {value=perty(key);}returnvalue;}}获取配置⽂件属性加载了配置⽂件,需要编写⼀个类ConfigHelper来获取配置⽂件属性。框架初始化需要根据配置⽂件来初始化应⽤。框架默认配置⽂件为ties,只有创建了名为ties的配置⽂件,框架才能运⾏。/*** 获取配置⽂件属性*/public classConfigHelper {private static final Properties CONFIG_PROPS = ops("ties");//默认配置⽂件为ties/*** 获取应⽤基础包名**@return*/public staticString getAppBasePackage() {ing(CONFIG_PROPS, _BASE_PACKAGE);}/*** 获取JSP路径**@return*/public staticString getAppJspPath() {ing(CONFIG_PROPS, _JSP_PACKAGE);}/*** 获取应⽤静态资源路径**@return*/public staticString getAppAssetPath() {return ing(CONFIG_PROPS, _ASSET_PATH, "/asset/");}}类加载器实现⼀个类加载器ClassUtil来加载基础包下的所有的类。只有加载了这些类,框架才能对其进⾏初始化。获取当前线程的ClassLoader通过这个类加载器来加载类,获取指定包名下的所有的类,需要指定根据包名并将其转换为⽂件路径,读取class⽂件或jar包,获取指定的类名去加载类。/*** 获取类加载器**@return*/public staticClassLoader getClassLoader() {tThread().getContextClassLoader();}/*** 加载类**@paramclassName 类名称*@paramisInitialized 是否执⾏类的静态代码块*@return*/public static Class> loadClass(String className, booleanisInitialized) {Class>clazz;try{clazz=e(className, isInitialized, getClassLoader());}catch(ClassNotFoundException cnfe) {tackTrace();throw newRuntimeException(cnfe);}returnclazz;}/*** 获取指定包下所有类**@parampackageName*@return*/public static ArrayList>getClasses(String packageName) {ArrayList> classes = new ArrayList<>();try{Enumeration urls = getClassLoader().getResources(e(".", "/"));while(eElements()) {URL url=ement();if (url != null) {String protocol=tocol();if (("file")) {String packagePath= h().replaceAll("%20", " ");addClass(classes, packagePath, packageName);}else if (("jar")) {JarURLConnection jarURLConnection=(JarURLConnection) nnection();if (jarURLConnection != null) {JarFile jarFile=File();if (jarFile != null) {Enumeration jarEntries =s();while(eElements()) {JarEntry jarEntry=ement();String jarEntryName=e();if ((".class")) {String className= ing(0, dexOf(".")).replaceAll("/", ".");doAddClass(classes, className);}}}}}}}}catch(Exception e) {tackTrace();throw newRuntimeException(e);}returnclasses;}.........}定义注解本框架采⽤注解来标识Controller,Service类。所以需要定义注解来标识那些类是Controller,Controller类中那些⽅法响应url请求等。控制器类上使⽤Controller注解,在控制器类的⽅法上使⽤RequestMapping注解,使⽤Autowired注解将服务类依赖注⼊进来。服务类使⽤Service注解。/*** 控制器注解*/@Target()@Retention(E)public @interfaceController {}/*** 请求⽅法注解*/@Target()@Retention(E)public @interfaceRequestMapping {//请求类型路径String path();//请求⽅法String method();}/*** 服务类注解*/@Target()@Retention(E)public @interfaceService {}/*** 依赖注⼊注解*/@Target()@Retention(E)public @interfaceAutowired {}获取类Controller,Service类是框架需要管理的类,把他们统称为Bean类。实现⼀个类可以获取应⽤所有的Controller,Service类。⾸先调⽤BasePackage()获取基础包名,然后调⽤sses(basePackage)加载该基础包名下所有的类,保存在变量ArrayList> classes中;再遍历ArrayList> classes获取Controller,Service等类。//获取类public classClassHelper {//基础包名下所有的类private static final ArrayList>classes;static{String basePackage=BasePackage();classes=sses(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 (tationPresent()) {(c);}}returncc;}/*** 框架Bean容器主要管理Service,Controller类**@return*/public static ArrayList>getBeanClasses() {ArrayList> bc = new ArrayList<>();(getServiceClasses());(getControllerClasses());returnbc;}}现在来测试类加载器和获取类是否正确,配置⽂件将基础包名设为_package=ller,在这个包下,实现了三个类HomeController类(带Controller注解),PersonService类(带Service注解),Person类。public static voidmain(String[]args) {ArrayList> ces =sses();for (Class>c : ces) {n(pleName());}}Bean⼯⼚回顾下前⾯的知识,通过加载配置⽂件获取应⽤基础包名,加载基础包名下所有的类,获取Controller,Service类。到⽬前为⽌,我们只是加载了类,但是⽆法通过获取的类来实例化对象。因此需要⼀个反射⼯具,来实例化类。创建⼀个Bena⼯⼚,来⽣产(实例化Bean类对象)Bean。newInstance()⽅法,实例化⽬标类;invokeMethod()通过反射机制来调⽤类中的⽅法;setField()通过反射机制为类成员遍历赋值。//Bean⼯⼚public classBeanFactory {/*** 创建实例**@paramclazz*@return*/public static Object newInstance(Class>clazz) {Object instance;try{instance=tance();}catch(Exception e) {throw newRuntimeException(e);}returninstance;}/*** ⽅法调⽤**@paramobj*@parammethod*@paramargs*@return*/public staticObject invokeMethod(Object obj, Method method, args) {Object result;try{essible(true);result=(obj, args);}catch(Exception e) {throw newRuntimeException(e);}returnresult;}/*** 设置成员变量值**@paramobj*@paramfield*@paramvalue*/public static voidsetField(Object obj, Field field, Object value) {try{essible(true);(obj, value);}catch(Exception e) {throw newRuntimeException(e);}}}Bean容器前⾯在ClassHelper定义了⽅法getBeanClasses()来获取Bean容器需要管理的所有Controller,Service类,获取这些类以后,调⽤tance(Class clazz)⽅法来实例化类的对象,缓存在Map beanContainer中,需要随时获取。Map说明:使⽤类全名称作为key,类的实例对象作为value值。BeanContainer初始化:⾸先调⽤nClasses()获取所有的Bean类,调⽤Bean⼯⼚⽅法newInstance()⽅法来实例化Bean类,保存在beanContainer中。通过类全名称从beanContainer获取需要的Bean实例对象。/*** Bean容器*/public classBeanContainer {/*** 存放Bean类名称和Bean实例的映射关系*/private static final Map beanContainer = new HashMap<>();static{ArrayList> beanClasses =nClasses();for (Class>beanClass : beanClasses) {Object obj=tance(beanClass);(e(), obj);}}/*** 获取Bean映射**@return*/public static MapgetBeanContainer() {returnbeanContainer;}/*** 获取Bean实例*/public static T getBean(String className) {if (!nsKey(className)) {throw new RuntimeException("cannot get bean by className: " +className);}return(T) (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 =nContainer();if(mpty(beanContainer)) {initIOC(beanContainer);}}private static void initIOC( MapbeanContainer) {for (eanEntry : et()) {String className=();Object beanInstance=ue();Class> beanClass = null;try{beanClass=e(className);n(className);}catch(ClassNotFoundException e) {tackTrace();}//Controller类中定义的属性Field[] beanFields =laredFields();if(mpty(beanFields)) {for(Field beanField : beanFields) {//带有Autowired注解的成员变量if (tationPresent()) {//成员变量的类Class> beanFieldClass =e();Object beanFieldInstance=(e());if (beanFieldInstance != null) {//依赖注⼊ld(beanInstance, beanField, beanFieldInstance);}}}}}}}RequestController类中带有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) {tMethod=requestMethod;tPath =requestPath;}publicString getRequestMethod() {returnrequestMethod;}publicString getRequestPath() {returnrequestPath;}@Overridepublic inthashCode() {return tionHashCode(this);}@Overridepublic booleanequals(Object obj) {return tionEquals(this,obj);}}/*** 处理Request请求对应Controller & method*/public classHandler {private Class>controllerClass;privateMethod method;public Handler(Class>controllerClass,Methodmethod) {llerClass =controllerClass; =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 =trollerClasses();if(mpty(controllerClasses)) {initRequestMapp(controllerClasses);}}private static void initRequestMapp(ArrayList>controllerClasses) {for (Class>controllerClass : controllerClasses) {Method[] methods=laredMethods();if(mpty(methods)) {for(Method method :methods) {//带有RequestMapping注解的⽅法if (tationPresent()) {RequestMapping rm= otation();//请求路径与请求⽅法Request request = newRequest((), ());//对应请求路径与请求⽅法的Controller和methodHandler handler = newHandler(controllerClass, method);(request, handler);}}}}}/*** 获取handler**@paramrequestMethod*@paramrequestPath*@return*/public staticHandler getHandler(String requestMethod, String requestPath) {Request request= newRequest(requestMethod, requestPath);(request);}}初始化类框架基本搭建起来了,现在需要编写⼀个类来初始化应⽤。初始化步骤:1、加载ClassHelper类,通过这个类加载基础包名下所有的类。2、加载BeanContainer类,将基础包名下所有Bean类,通过Bean⼯⼚实例化保存在Bean容器。3、加载IocHelper类,实例化Bean类,需要为Controller类中带有Autowired注解的属性赋值。4、加载ControllerHelper类,将Controller类中带有RequestMapping注解的⽅法,建⽴与请求路径和请求⽅法的映射关系,这样框架才能找到处理请求对应的⽅法。/*** 初始化框架*/public classLoader {public static voidinit() {Class>[] cs = {,,,};for (Class>c: cs) {ass(e(),true);}}}请求参数通常前端通过form表格的形式向后台发送数据,需要⼀个类封装从HttpServletRequest请求对象中获取所有的参数,然后传递给处理⽅法。⾸先解析请求参数(form表单数据),将其封装成Param类中,传递给Controller的⽅法处理。通过ameterNames()将发送请求页⾯中form表单所具有name属性的表单对象获取,ameterValues(name)获取其值,⽣成FormParam保存在Param中。/*** 解析请求参数,form表单数据*/public classParameterUtil {public static Param createParam(HttpServletRequest request) throwsIOException {returnnewParam(parseParameterNames(request));}private static MapparseParameterNames(HttpServletRequest request) {Map formParams = new HashMap<>();//将发送请求页⾯中form表单所具有name属性的表单对象获取Enumeration paramNames =ameterNames();while(eElements()) {String fieldName=ement();String[] fieldValues=ameterValues(fieldName);if(mpty(fieldValues)) {Object fieldValue;if ( == 1) {fieldValue= fieldValues[0];}else{StringBuilder sb= new StringBuilder("");for (int i = 0; i < ; ++i) {(fieldValues[i]);if (i != - 1) {(tor);}}fieldValue=ng();}(fieldName,fieldValue);}}returnformParams;}}Param请求参数对象,封装了前端提交的form表格数据。/*** 请求参数对象*/public classParam {private MapformParams;public Param(MapformParams) {rams =formParams;}/*** 判断参数是否为空**@returnboolean*/public booleanisEmpty() {y(formParams);}public MapgetFormParams() {returnformParams;}/*** 根据参数名取String型参数值**@paramname*@return*/publicString getString(String name) {ring((name));}public doublegetDouble(String name) {uble((name));}public longgetLong(String name) {ng((name));}public intgetInt(String name) {t((name));}publicBoolean getBoolean(String name) {olean((name));}}模型数据与视图在处理请求时,通常会返回视图JSP页⾯和数据。所以现在需要将视图JSP路径和数据封装在⼀起返回。如果只返回数据,则返回JSON格式数据。返回视图JSP,视图中包含视图JSP路径和视图中所需的数据:public classModelAndView {//返回JSP路径privateString path;//模型数据private MapmData;publicModelAndView(String path) { =path;mData= new HashMap<>();}publicModelAndView addmData(String key, Object obj) {(key,obj);return this;}publicString getPath() {returnpath;}public MapgetmData() {returnmData;}}返回数据,框架将其写⼊HttpServletRespone对象中,输出到客户端浏览器。/*** 返回数据*/public class Data{privateT datas;publicData(T 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=alueAsString(obj);}catch(Exception e) {tackTrace();}returnjson;}/*** 将JSON转化为POJO**@paramjson*@paramclazz*@param*@return*/public static T fromJSON(String json, Classclazz) {T pojo= null;try{ObjectMapper mapper= newObjectMapper();pojo=lue(json, clazz);}catch(Exception e) {tackTrace();}returnpojo;}}请求转发器请求转发器是框架的核⼼。请求转发器转发器⽤来处理所有的请求。DispatherServlet继承HttpServlet,在init()⽅法调⽤()来初始化框架和应⽤。service()⽅法响应所有的请求。请求转发过程:1、通过hod().toLowerCase()获取请求⽅法(get,post,put delete);textPath()获取请求路径,根据请求路径和请求⽅法调⽤dler()⽅法获取处理这个请求对应的handler。2、Hanler封装处理请求的Controller和⽅法,所有获取的handler,就可以获取处理请求的Controller和⽅法method。3、获取了处理这个请求的Controller类,现在需要在Bean获取这个Controller类的实例对象,调⽤n()来获取Controller类的实例对象。4、调⽤Param(req)来解析请求参数。5、调⽤hod()获取处理这个请求的⽅法,通过反射机制Method()来调⽤这个⽅法,处理这个请求的⽅法就会来处理这个请求。6、根据返回的结果是ModelAndView还是Data来处理返回问题。返回结果为ModelAndView,调⽤uestDispatcher(JspPath() + path).forward(req, resp)将页⾯响应转发到JspPath() + path;返回结果为Data,将返回结果POJO转换为JSON格式,写⼊HttpServletRespone对象中,输出到客户端浏览器。/*** 请求转发器*/@WebServlet(urlPatterns= "/",loadOnStartup = 0)public class DispatherServlet extendsHttpServlet {@Overridepublic void init(ServletConfig config) throwsServletException {();//初始化框架&应⽤ServletContext sc =vletContext();//注册JSP的ServletServletRegistration jspServlet = vletRegistration("jsp");ping(JspPath()+ "*");//注册处理静态资源的ServletServletRegistration defaultServlet = vletRegistration("default");ping(AssetPath()+ "*");}@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throwsServletException, IOException{//获取请求⽅法String requestMethod =hod().toLowerCase();//请求路径urlString url =uestURI();String contextPath=textPath();String requestPath= null;if (contextPath != null && () > 0) {requestPath=ing(());}//获取处理这个请求的handlerHandler handler =dler(requestMethod, requestPath);//n(requestMethod + " " +requestPath);if (handler != null) {Class> controllerClass =trollerClass();Object controllerBean=n(e());//解析请求参数Param param =Param(req);Object result;//请求返回对象Method method = hod();//处理请求的⽅法if(y()) {result=Method(controllerBean, method);}else{result=Method(controllerBean, method, param);}if (result instanceofModelAndView) {handleViewResult((ModelAndView) result, req, resp);}else{handleDataResult((Data) result, resp);}}}//返回为JSP页⾯private static voidhandleViewResult(ModelAndView view, HttpServletRequest req, HttpServletResponseresp)throwsIOException, ServletException {String path=h();if(mpty(path)) {if (With("/")) {direct(textPath()+path);}else{Map data =ta();for (ntry : et()) {ribute((), ue());}//forward将页⾯响应转发到JspPath() + path//补全代码}}}//返回JSON数据private static voidhandleDataResult(Data data, HttpServletResponse resp)throwsIOException {Object model=a();if (model != null) {tentType("application/json");racterEncoding("UTF-8");PrintWriter writer=ter();String json=(model);(json);();();}}}---汇智⽹

发布者:admin,转转请注明出处:http://www.yc00.com/web/1690581275a372869.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信