您的位置:澳门皇家赌场真人在线 > 皇家赌场游戏 > 协调手写七个SpringMVC框架,thymeleaf全局常量定义

协调手写七个SpringMVC框架,thymeleaf全局常量定义

发布时间:2019-10-04 15:43编辑:皇家赌场游戏浏览(67)

    JDK:

    java development kit, java开拓工具包,针对开垦者,里面根本富含了jre, jvm, jdk源码包,以及bin文件夹下用于支付,编写翻译运转的部分指令器。

    图片 1image.png

    软件的国际化:软件开采时,要使它能相同的时间应对社会风气不一样地区和国家的探访,并针对分化地段和国度的拜谒,提供对应的、切合来访者阅读习贯的页面或数量。

    不久前进展组内分享时接纳了那一个Java字节码管理那几个主旨,特此记录下来。名闻遐迩,Java是一门运维在设想机上的语言,在开立之初正是为着"write once ,run anywhere "的指标,为了减轻区别架构管理器差距,通过虚拟机来蒙蔽分化的依次操作系统之间的分化,其虚构机上运转的平台中立的二进制文件正是class字节码文件,当然JIT,AOT之类的本领是后来为了让Java运转更加快参加的,然则这里我们只是对Java的字节码文件的管理。ASM是怎么着吧,ASM是贰个Java字节码等级次序的拍卖框架。它能够一贯对class文件实行增加和删除改的操作,Java中非常多的框架的实现就是基于ASM,例如AOP的兑现,Java自己的动态代理只能帮衬接口的格局,而采纳ASM就会很有益于的扩展到类的代办。能够说ASM正是一把利剑,是深刻Java必得学习的一个点。本章重要透过以下几点来解析ASM

    微服务未来最盛行的骨子里springboot,官方推荐二种模板语言,freemarker和thymeleaf,本文只介绍thymeleaf中如何定义全局常量。百度一搜thymeleaf的全局常量定义,都以让把常量写在“message_*”文件中,当然,做国际化的时候那么些没问题,然则随着未来微服务大行其道,有众多不是国际化的东西需求定义,比方服务A调用服务B,那时候必定要在A中配置B的url,那时候再写入message鲜明不适于了。

    JRE:

    java runtime environment, java运维时意况,针对java顾客,也正是有所可运转的.class文件包的顾客。里面根本包括了jvm和java运营时基本类库。rt.jar能够总结凶狠地知道为:它正是java源码编写翻译成的jar包,用eclipse开采时,当您ctrl点击开掘无法跳转到源文件时,必要把rt.jar对应的源码包加进来,而这边的源码包正是jdk文件夹下的src.zip。

    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ghgcn</groupId> <artifactId>myspringmvc</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>myspringmvc</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build></project>
    

    协调手写七个SpringMVC框架,thymeleaf全局常量定义。前后相继:必要国际化。

    • ASM的基本功运用
    • ASM的设计情势
    • Class的文件格式
    • ASM的源码分析
    • ASM总结

    常规先上思路

    在模板深入分析时候就将常量写入,重写模板分析配置情势。看springboot源码

    public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer { /** * {@inheritDoc} * <p>This implementation is empty. */ @Override public void configureViewResolvers(ViewResolverRegistry registry) { }}
    

    目测应该是重写那货就可以了,talk is cheap,show me the code

    JVM:

    正是大家常说的java虚构机,它是一体java达成跨平台的最大旨的有些,全部的java程序会首先被编译为.class的类公事,那种类公事能够在虚构机上实施。

    也正是说class并不直接与机械和工具的操作系统相呼应,而是通过虚拟机直接与操作系统交互,由虚构机将次第解释给本地系统推行。

    独有JVM还无法成class的进行,因为在分解class的时候JVM供给调用解释所急需的类库lib,而jre满含lib类库。

    JVM屏蔽了与具象操作系统平台相关的消息,使得Java程序只需转换在Java设想机上运转的对象代码,就足以在三种平台上不加修改地运营。

    去bin文件夹下你会开掘,JDK有javac.exe而JRE里面未有,人人皆知javac指令是用来将java文件编写翻译成class文件的,那是您付出去做的事,客商是不会去做的。JDK还恐怕有jar.exe, javadoc.exe等等用于开采的可实践指令文件。那也认证了叁个是开荒情形,叁个是运作条件。

    有一些人感觉,JVM就足以实施class了,其实不然,JVM施行.class还亟需JRE下的lib类库的帮忙,特别是rt.jar。

    图片 2三者关系图

    web.xml

    <?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <!-- 前端控制器 --> <servlet> <servlet-name>MyDispatcherServlet</servlet-name> <servlet-class>com.ghgcn.myspringmvc.servlet.MyDispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!--配置文件 --> <param-value>classpath:application.properties</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MyDispatcherServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <!--字符编码 --> <filter> <filter-name>UTF8Filter</filter-name> <filter-class>com.ghgcn.myspringmvc.filter.UTF8Filter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>UTF8Filter</filter-name> <url-pattern>/</url-pattern> </filter-mapping></web-app>
    

    多少:是怎么的正是怎么的。

    对此ASM的选拔最推荐的莫过于官方的 《ASMGuide》,介绍的非常详细。这里先投砾引珠给出叁个相比轻易的例子,引出ASM中最要害的多少个类。假诺我们有一个急需是给多个class文件增添三个田野先生字段,代码如下

    初始重写

    1.现行反革命Application.properties中定义七个常量,用于文书上传和预览

    upload.path=http://localhost:9091/accessory/uploadimage.view.path=http://localhost:9091/accessory/open?id=
    

    2.重写configureViewResolvers(ViewResolverRegistry registry)

     @Resource(name="thymeleafViewResolver") private ThymeleafViewResolver thymeleafViewResolver; @Value("${upload.path}") private String defaultUploadPath; @Value("${image.view.path}") private String defaultImageViewPath; @Override public void configureViewResolvers(ViewResolverRegistry registry) { if (thymeleafViewResolver != null) { Map<String, Object> vars = new HashMap<>; vars.put("uploadPath", defaultUploadPath); vars.put("defaultImageViewPath", defaultImageViewPath); thymeleafViewResolver.setStaticVariables; } super.configureViewResolvers; }
    

    3.模板上行使html中

    <img src="/images/default-mem.png" th:src="${defaultImageViewPath+user.photo}" alt="图片 3" >
    

    js中写法比较奇怪, /<![CDATA[/ 中间写定义的全局js常量 /]]>/

     <script th:inline="javascript"> /*<![CDATA[*/ var basePath='http://www.baidu.com'; var uploadPath=[[${uploadPath}]]; var defaultImageViewPath=[[${defaultImageViewPath}]]; /*]]>*/ </script>
    

    正是酱紫。

    流行框架

    SpringCloudspringbootnginxredis

    properties

    basePackage=com.ghgcn.myspringmvc
    

    比如:

    public class AddField extends ClassVisitor { private String name; private int access; private String desc; private Object value; private boolean duplicate; public AddField(ClassVisitor cv, String name, int access, String desc, Object value) { super; this.name = name; this.access = access; this.desc = desc; this.value = value; } @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { if (this.name.equals { duplicate = true; } return super.visitField(access, name, desc, signature, value); } @Override public void visitEnd() { if (!duplicate) { FieldVisitor fv = super.visitField(access, name, desc, null, value); if (fv != null) { fv.visitEnd(); } } super.visitEnd(); } public static void main(String[] args) throws Exception { String output = System.getProperty("user.dir") + "/libjava/output"; String classDir = System.getProperty("user.dir") + "/libjava/output/MainActivity.class"; ClassReader classReader = new ClassReader(new FileInputStream); ClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS); ClassVisitor addField = new AddField(classWriter, "field", Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, Type.getDescriptor(String.class), "value" ); classReader.accept(addField, ClassReader.EXPAND_FRAMES); byte[] newClass = classWriter.toByteArray(); File newFile = new File(output, "MainActivity1.class"); new FileOutputStream.write; }}
    
    底层达成原理:

    Java NIO教程Java reflection 反射详解Java并发学习笔录Java Servlet教程jdbc组件详解Java NIO教程Java语言/版本 研讨

    注解

    /** * 控制器 * @author Administrator * */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyController { /** * 表示给controller注册别名 * @return */ String value() default "";}/** * 请求路径 * @author Administrator * */@Target(value={ElementType.METHOD,ElementType.TYPE})@Documented@Retention(RetentionPolicy.RUNTIME)public @interface MyRequestMapping { /** * 表示访问该方法的url * @return */ String value() default "";}/** * 参数 * @author Administrator * */@Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface MyRequestParam { /** * 表示参数的别名,必填 * @return */ String value();}
    

    顾客注册的表单,有客商名,密码这5个汉字,在zh_CN语言情形,显示的便是顾客名和密码。可是在en_US语言境遇,展现的就应当是username和password。那正是先后。

    这段代码是给两个Class文件多加三个字段的操作,在ASM的包装下,那样的操作完毕非常轻易,下边大家就将学习到ASM是何等造成这一体的。

    helper

    public class IOHelper { public static void close(AutoCloseable closeable) { try { if (closeable != null) { closeable.close(); } } catch (Exception e) { e.printStackTrace(); } }}
    

    顾客名输入的是,密码输入的是,那无论是在哪些语言情状都应有是是和。那正是数据。

    以前方的ClassVisitor以及accept方法就能够看见那是众所周知的visitor方式,visitor方式在Java的设计情势中是一种极冰冷门的设计情势,冷门并非因为这么些方式的先天不足,而是相较于一些作风相比显明的诸如单例,工厂,观看者格局,访谈者方式的实际上采纳场景是少之甚少的,前面会介绍到这一个方式其实存在的一个比相当大的难点。访谈者方式主要包括被访问的因素以及媒体人两局地,成分日常是见仁见智的体系,不一样的访谈者对于这几个成分的操作日常也是例外的,新闻报道人员方式使得客户可以在不改换现成系统的情形下扩展系统的魔法,为那一个分裂类其余成分扩大新的操作。报事人的格局教学相比好的文章能够看那篇,操作复杂对象组织——访谈者格局相似新闻报道人员方式的成分会经受三个访谈者的参数,在要素内部这些媒体人会一贯访谈这些因素,说的比较绕,用代码来分解

    过滤器

    package com.ghgcn.myspringmvc.filter;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletResponse;public class UTF8Filter implements Filter { private String encoding="UTF-8"; /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { String initParameter = fConfig.getInitParameter("encoding"); if(initParameter!=null){ this.encoding=initParameter; } } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding; chain.doFilter(request, response); HttpServletResponse resp = (HttpServletResponse)response ; resp.setCharacterEncoding; } @Override public void destroy() { }}
    
    package com.ghgcn.myspringmvc.servlet;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.URL;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import java.util.Properties;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.ghgcn.myspringmvc.annotation.MyController;import com.ghgcn.myspringmvc.annotation.MyRequestMapping;import com.ghgcn.myspringmvc.helper.IOHelper;public class MyDispatcherServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 7613183580743740653L; /** * 属性-加载配置文件 */ private Properties properties = new Properties(); /** * 所有类的名称 */ private List<String> classNames = new ArrayList<>(); /** * 注入的容器 */ private Map<String, Object> ioc = new HashMap<>(); /** * 请求地址映射-controller-方法 */ private Map<String, Method> handlerMapping = new HashMap<>(); /** * 控制器 */ private Map<String, Object> controllerMap = new HashMap<>(); @Override public void init(ServletConfig config) throws ServletException { // 1.加载配置文件 doLoadConfig(config.getInitParameter("contextConfigLocation")); // 2.初始化所有相关联的类,扫描用户设定的包下面所有的类 基础包下的所有类的全路径名称com.xx.xx.类名 doScanner(properties.getProperty("basePackage")); // 3.拿到扫描到的类,通过反射机制,实例化,并且放到ioc容器中(k-v beanName-bean) beanName默认是首字母小写 doInstance(); // 4.初始化HandlerMapping(将url和method对应上) initHandlerMapping(); } /** * 1.加载启 到的配置 * * @param location */ private void doLoadConfig(String location) { System.out.println("location "+location); if(location.startsWith("classpath:")){ location=location.substring(location.indexOf; } /** * 加载文件 -application.properties */ InputStream inStream = this.getClass().getClassLoader().getResourceAsStream; try { this.properties.load; } catch (IOException e) { e.printStackTrace(); } finally { if (inStream != null) { IOHelper.close; } } } /** * 2.扫描包,基础包下的所有类的全路径名称com.xx.xx.类名 * * @param property */ private void doScanner(String packageName) { // 1.把所有的.替换成/ URL url = this.getClass().getClassLoader().getResource(packageName.replace); System.out.println("url " + url.getFile; /** * 2.获取所有文件 */ File file = new File(url.getFile; for (File f : file.listFiles { if (f.isDirectory { // 递归 doScanner(packageName + "." + f.getName; } else { String className = packageName + "." + f.getName().replace(".class", ""); System.out.println("className " + className); /** * 反所有类都放在这个集合中-类的全路径 */ classNames.add(className); } } } /** * 3 拿到扫描到的类,通过反射机制,实例化,并且放到ioc容器中(k-v beanName-bean) beanName默认是首字母小写 */ private void doInstance() { if (classNames.isEmpty { return; } for (String classname : classNames) { try { //反射来实例化(只有加@MyController需要实例化) Class<?> clazz = Class.forName(classname); if (clazz.isAnnotationPresent(MyController.class)) { // 放入IOC容器 类首字母小写, 通过无参构造方法获取实例 ioc.put(toLowerFirstWord(clazz.getSimpleName, clazz.newInstance; } else { continue; } } catch (ClassNotFoundException e) { e.printStackTrace(); continue; } catch (InstantiationException e) { e.printStackTrace(); continue; } catch (IllegalAccessException e) { e.printStackTrace(); continue; } } } /** * 4.将请求的url与method中的方法对应 */ private void initHandlerMapping() { if (ioc.isEmpty { return; } try { for (Map.Entry<String, Object> entry : ioc.entrySet { Class<? extends Object> clazz = entry.getValue().getClass(); /** * 判断如果不是MyController 的注解,就下一个 */ if (!clazz.isAnnotationPresent(MyController.class)) { continue; } // 拼url时,是controller头的url拼上方法上的url String baseUrl = ""; if (clazz.isAnnotationPresent(MyRequestMapping.class)) { MyRequestMapping contollerAnnotation = clazz.getAnnotation(MyRequestMapping.class); baseUrl = contollerAnnotation.value(); } /** * 获取所有方法的请求myrequestiongmapping */ Method[] methods = clazz.getMethods(); for (Method method : methods) { if (!method.isAnnotationPresent(MyRequestMapping.class)) { continue; } MyRequestMapping methodAnnotation = method.getAnnotation(MyRequestMapping.class); /** * 方法的请求路径 */ String methodUrl = methodAnnotation.value(); /** * 拼接 */ String url = (baseUrl + "/" + methodUrl).replaceAll("/+", "/"); System.out.println("url " + url + " method " + method); /** * 将url与method做关联 */ handlerMapping.put(url, method); /** * 控制器 -- 请求地址与控制器关系 */ controllerMap.put(url, clazz.newInstance; } } } catch (Exception e) { e.printStackTrace(); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { // 处理请求 resp.setHeader("Content-type", "text/html;charset=UTF-8"); doDispatch(req, resp); } catch (Exception e) { resp.getWriter().write("500!! Server Exception"); } } /** * 处理请求 * * @param req * @param resp * @throws IOException */ private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (handlerMapping.isEmpty { return; } /** * 获取请求路径 */ String url = req.getRequestURI(); /** * 上下路径 */ String contextPath = req.getContextPath(); url = url.replace(contextPath, "").replaceAll("/+", "/"); /** * 判断请求路径是否存在 */ if (!handlerMapping.containsKey { resp.getWriter().write("404 Not found"); return; } /** * 获取请求的方法 */ Method method = handlerMapping.get; /** * 获取方法的参数 */ Class<?>[] parameterTypes = method.getParameterTypes(); /** * 获取请求的方法的请求参数 */ Map<String, String[]> requestparameterMap = req.getParameterMap(); /** * 保存参数值 */ Object[] paramValues = new Object[parameterTypes.length]; /** * 方法的参数列表 */ for (int i = 0; i < paramValues.length; i++) { String requestParam = parameterTypes[i].getSimpleName(); System.out.println("requestParam "+requestParam); /** * 请求 */ if (requestParam.equals("HttpServletRequest")) { // 参数类型已明确,这边强转类型 paramValues[i] = req; continue; } /** * 响应 */ if (requestParam.equals("HttpServletResponse")) { paramValues[i] = resp; continue; } /** * 参数转换为 */ if (requestParam.equals) { for (Entry<String, String[]> param : requestparameterMap.entrySet { System.out.println("param "+param); String value = Arrays.toString(param.getValue.replaceAll("\[|\]", "").replaceAll(",\s", ","); System.out.println("value "+value); paramValues[i] = value; } } /** * 通过反射来执行方法 * /第一个参数是method所对应的实例 在ioc容器中 */ } try { method.invoke(controllerMap.get, paramValues); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } } /** * 把字符串的首字母小写 * * @param name * @return */ private String toLowerFirstWord(String name) { char[] charArray = name.toCharArray(); charArray[0] += 32; return String.valueOf(charArray); }}
    

    比如说:音讯提醒,错误提示和菜单,导航栏等等固定文本。

    public interface Employee { public void accept(Department handler);}
    

    测试

    package com.ghgcn.myspringmvc.action;import java.io.IOException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.ghgcn.myspringmvc.annotation.MyController;import com.ghgcn.myspringmvc.annotation.MyRequestMapping;import com.ghgcn.myspringmvc.annotation.MyRequestParam;@MyController@MyRequestMappingpublic class TestController { @MyRequestMapping("/doTest") public void test1(HttpServletRequest request, HttpServletResponse response, @MyRequestParam String param) { System.out.println("============test1============="); System.out.println; try { //response.setHeader("Content-type", "text/html;charset=UTF-8"); response.getWriter().write("doTest method success! param:" + param); } catch (IOException e) { e.printStackTrace(); } } @MyRequestMapping("/doTest2") public void test2(HttpServletRequest request, HttpServletResponse response,String test) { System.out.println("==========test2======="); System.out.println; try { //response.setHeader("Content-type", "text/html;charset=UTF-8"); response.getWriter().write("doTest2 method success!"); response.getWriter().write; } catch (IOException e) { e.printStackTrace(); } }}
    

    图片 4image.png图片 5image.png

    步骤:

    先是对此成分类大家提供三个接口,内部的不二法门正是accept,用来接过三个访谈者类

    本文由澳门皇家赌场真人在线发布于皇家赌场游戏,转载请注明出处:协调手写七个SpringMVC框架,thymeleaf全局常量定义

    关键词: