-
2018-10-29 20:16:48
spring mvc配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 设置默认配置方案 --> <mvc:annotation-driven /> <!-- 包扫描,将注解的类注入 --> <context:component-scan base-package="xyz.cglzwz.controller"/> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.InternalResourceView"/> <!-- 前缀(目录) --> <property name="prefix" value="/" /> <!-- 后缀(文件名) --> <property name="suffix" value=".jsp"/> </bean> </beans>
配置视图解析器后控制器可以直接返回String类型的页面文件名来指定需要跳转的页面视图
控制器代码
package xyz.cglzwz.controller; import org.apache.ibatis.logging.Log; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import xyz.cglzwz.domain.User; import xyz.cglzwz.service.UserService; /** * 用户登录控制器 * * @author chgl16 * @date 2018-10-28 23:31 * @version 1.0 */ @Controller public class LoginController { private final Logger log = Logger.getLogger(this.getClass()); @Autowired private UserService userService; @Autowired private User user; @RequestMapping(value = "/login", method = RequestMethod.GET) public String login(@RequestParam String username, @RequestParam String password) { user.setUsername(username); user.setPassword(password); if (userService.isRegister(user)) { // 已经注册 log.info("用户" + username + "已经注册,可以登录"); if (userService.isCorrectPassword(user)) { // 密码正确 log.info("密码正确, 正在登录...."); // 会跳转到index.jsp (配置了url视图配置器) return "index"; } else { log.info("密码错误"); return "errorPassword"; } } else { log.info("用户" + username + "尚未注册"); return "errorNoRegistered"; } } }
更多相关内容 -
PE文件解析类(轻松制作自己的PE文件解析器)
2016-02-06 21:10:24同时该类也可以让想创建自己的PE文件解析软件的朋可以轻松在此基础上实现。 最后,错误在所难免,如果大家发现有错误,欢迎大家指正。 具体参看:http://blog.csdn.net/paschen/article/details/50640421 -
so文件解析
2015-10-22 19:03:28使用C++解析一个so文件,很是使用的一个工具类。 -
C++PE文件格式解析类(轻松制作自己的PE文件解析器)
2016-02-06 18:05:11用C++封装了可以轻松高效获取PE文件中各信息的类,该类有较高可读性,同时具有一定的通用性,适合学习,也适合轻松实现自己的PE文件信息查看软件PE是Portable Executable File Format(可移植的执行体)简写,它是目前Windows平台上的主流可执行文件格式。
PE文件中包含的内容很多,具体我就不在这解释了,有兴趣的可以参看之后列出的参考资料及其他相关内容。
最近我也在学习PE文件格式,参考了许多资料,用C++封装了一个高效方便的PE文件格式解析的类。
该类对想学PE文件结构的朋友可算一份可贵的资料,代码均很易懂,考虑较全面,具有一定的通用性。
同时该类也可以让想创建自己的PE文件解析软件的朋可以轻松在此基础上实现。
最后,错误在所难免,如果大家发现有错误,欢迎大家指正。
以下是该类中接口函数的定义代码(完整代码附于之后下载链接中):
<pre name="code" class="cpp">class CPeFile { public: CPeFile(); ~CPeFile(); // 以下函数无特殊说明任何时候均可用 public: //将PE文件附加到对象,成功返回IMAGE_DOS_SIGNATURE、IMAGE_OS2_SIGNATURE、IMAGE_OS2_SIGNATURE_LE、IMAGE_NT_SIGNATURE之一;失败返回0UL(未知类型),1UL(文件操作失败),2(其他错误),【仅在没有PE文件附加到类对象时可用】 DWORD Attach(LPCTSTR lpszFilePath); //若已有PE文件附加到类对象则释放关联 void Detach(); //获取Attach信息,成功返回IMAGE_DOS_SIGNATURE、IMAGE_OS2_SIGNATURE、IMAGE_OS2_SIGNATURE_LE、IMAGE_NT_SIGNATURE之一;未成功返回0UL DWORD GetAttachInfo() const; // 以下函数无特殊说明Attach成功后均可用 public: //获取文件句柄(注:不应在外部执行CloseHandle等有副作用的操作) HANDLE GetFileHandle() const; //获取内存映射文件头部地址 DWORD_PTR GetMappedFileStart() const; //获取内存映射文件头部指定偏移位置(不应大于文件大小,否则返回的指针可能引起错误) DWORD_PTR GetMappedFileOffset(DWORD dwFoa) const; //获取DOS头 const IMAGE_DOS_HEADER* GetDosHeader() const; //获取DOS的入口地址 DWORD GetDosEntryPoint() const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE public: //获取PE文件头(如果是64位程序,返回的实际是const IMAGE_NT_HEADER64*)【类型为IMAGE_OS2_SIGNATURE、IMAGE_OS2_SIGNATURE_LE时仍可用,但操作需小心】 const IMAGE_NT_HEADERS32* GetNtHeader() const; //返回文件是否为64位(PE32+) BOOL Is64Bit() const; //获取PE文件头中的加载基地址ImageBase(64位程序返回的是ULONGLONG类型,32位程序可将返回值转换成DWORD类型) ULONGLONG GetImageBase() const; //获取PE文件头中的DataDirectory const IMAGE_DATA_DIRECTORY* GetDataDirectory() const; //获取各DataDirectory入口的RVA DWORD GetDataDirectoryEntryRva(DWORD dwIndex) const; //获取节表(节表的数量可由lpSectionNum传出) const IMAGE_SECTION_HEADER* GetSectionHeader(LPWORD lpSectionNum = NULL) const; //将RVA转换为FOA(可由lpFoa传出FOA、可由lpSection传出节序号,不在节中节序号为-1) BOOL RvaToFoa(DWORD dwRva, LPDWORD lpFoa = NULL, LPWORD lpSection = NULL) const; //将FOA转换为RVA(可由lpRva传出RVA、可由lpSection传出节序号,不在节中节序号为-1) BOOL FoaToRva(DWORD dwFoa, LPDWORD lpRva = NULL, LPWORD lpSection = NULL) const; //将VA转换为RVA(VA应大于ImageBase,函数中不检查) DWORD VaToRva(DWORD dwVa) const; DWORD VaToRva(ULONGLONG ullVa) const; //将RVA转换为VA(64位程序返回的是ULONGLONG类型,32位程序可将返回值转换成DWORD类型) ULONGLONG RvaToVa(DWORD dwRva) const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE public: //读取PE中导出表 BOOL ReadExport(); //读取PE中导入表 BOOL ReadImport(); //读取PE中资源表 BOOL ReadResource(); //读取PE中异常表 BOOL ReadException(); //读取PE中属性证书表 BOOL ReadSecurity(); //读取PE中基址重定位表 BOOL ReadBaseRelocation(); //读取PE中调试数据 BOOL ReadDebug(); //读取PE中线程局部存储表 BOOL ReadTLS(); //读取PE中加载配置表 BOOL ReadLoadConfig(); //读取PE中绑定导入表 BOOL ReadBoundImport(); //读取PE中延迟加载导入表 BOOL ReadDelayImport(); //清理PE中导出表 void ClearExport(); //清理PE中导入表 void ClearImport(); //清理PE中资源表 void ClearResource(); //清理PE中异常表 void ClearException(); //清理PE中属性证书表 void ClearSecurity(); //清理PE中基址重定位表 void ClearBaseRelocation(); //清理PE中调试数据 void ClearDebug(); //清理PE中线程局部存储表 void ClearTLS(); //清理PE中加载配置表 void ClearLoadConfig(); //清理PE中绑定导入表 void ClearBoundImport(); //清理PE中延迟加载导入表 void ClearDelayImport(); //清理所有 void ClearAll(); //返回是否读取了PE中导出表 BOOL IsReadExport() const; //返回是否读取了PE中导入表 BOOL IsReadImport() const; //返回是否读取了PE中资源表 BOOL IsReadResource() const; //返回是否读取了PE中异常表 BOOL IsReadException() const; //返回是否读取了PE中属性证书表 BOOL IsReadSecurity() const; //返回是否读取了PE中基址重定位表 BOOL IsReadBaseRelocation() const; //返回是否读取了PE中调试数据 BOOL IsReadDebug() const; //返回是否读取了PE中线程局部存储表 BOOL IsReadTLS() const; //返回是否读取了PE中加载配置表 BOOL IsReadLoadConfig() const; //返回是否读取了PE中绑定导入表 BOOL IsReadBoundImport() const; //返回是否读取了PE中延迟加载导入表 BOOL IsReadDelayImport() const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadExport成功 public: //获取导出表 const IMAGE_EXPORT_DIRECTORY* GetExportDirectory() const; //获取导出表中各导出函数地址数组(数量可由lpFuncNum传出) const DWORD* GetExportFunction(LPDWORD lpFuncNum = NULL) const; //获取导出表中被定义了名称的各导出函数名称地址数组(数量可由lpNameNum传出) const DWORD* GetExportName(LPDWORD lpNameNum = NULL) const; //获取导出表中被定义了名称的各导出函数的索引(数量可由lpNameNum传出) const WORD* GetExportNameOrdinal(LPDWORD lpNameNum = NULL) const; //解析导出函数地址数组中dwIndex项,返回值小于NumberOfNames为按名称导出(数值为序号),返回值等于NumberOfNames则为按序号导出 DWORD ParseExportFunction(DWORD dwIndex) const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadImport成功 public: //获取各导入表(导入表数量可由lpImportDescriptorNum传出) const IMAGE_IMPORT_DESCRIPTOR* GetImportDescriptor(LPDWORD lpImportDescriptorNum = NULL) const; //获取第iImpoert个导入表中的IMAGE_THUNK_DATA32结构(64位程序实际是IMAGE_THUNK_DATA64)(数量可由lpCount传出) const IMAGE_THUNK_DATA32* GetImportThunkData(DWORD iImport, LPDWORD lpCount = NULL) const; //解析某个IMAGE_THUNK_DATA32结构(64位程序实际是IMAGE_THUNK_DATA64),返回结果:1表示按序号导入(lpParam可传出序号);2表示按名称导入(lpParam可传出对应IMAGE_IMPORT_BY_NAME的FOA);0失败【只需要IMAGE_NT_SIGNATURE即可用】 int ParseThunkData(const IMAGE_THUNK_DATA32* lpThunk, LPDWORD lpParam = NULL) const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadResource成功 public: //获取第一层资源的ID,返回1表示第一层是目录,返回2表示第一层是数据,返回0表示无资源 int GetFirstResourceId(PIDTYPE lpFirstID) const; //获取下一层资源的ID,返回1表示下一层是目录,返回2表示下一层是数据,返回0表示无下一层 int GetNextResourceId(IDTYPE Id, DWORD iRes, PIDTYPE NextID) const; //解析Id对应的目录层,lpEntryNum可传出数组数量,lpLevel可传出第几级目录,lpResourceEntry传出本层对应的IMAGE_RESOURCE_DIRECTORY_ENTRY数组 const IMAGE_RESOURCE_DIRECTORY* ParseResourceDirectory(IDTYPE Id, LPDWORD lpEntryNum = NULL, LPDWORD lpLevel = NULL, IMAGE_RESOURCE_DIRECTORY_ENTRY** lpResourceEntry = NULL) const; //解析dwId对应的数据层 const IMAGE_RESOURCE_DATA_ENTRY* ParseResourceData(IDTYPE Id) const; //解析某个IMAGE_RESOURCE_DIRECTORY_ENTRY结构中Name成员,返回结果:1(dwParam为ID);2(dwParam为对应IMAGE_RESOURCE_DIR_STRING_U的FOA)【只需要IMAGE_NT_SIGNATURE即可用】 int ParseResourceDirectoryEntry(const IMAGE_RESOURCE_DIRECTORY_ENTRY* lpEntry, LPDWORD dwParam) const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadException成功 public: //获取异常表(数量可由lpRuntimeFunctionNum传出) const IMAGE_RUNTIME_FUNCTION_ENTRY* GetRuntimeFunction(LPDWORD lpRuntimeFunctionNum = NULL) const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadSecurity成功 public: //获取属性证书表(数量可由lpCertificateNum传出) const WIN_CERTIFICATE* const* GetCertificate(LPDWORD lpCertificateNum = NULL) const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadBaseRelocation成功 public: //获取各基址重定位表(数量可由lpBaseRelocationNum传出) const IMAGE_BASE_RELOCATION* const* GetBaseRelocation(LPDWORD lpBaseRelocationNum = NULL) const; //获得某个基址重定位表中的重定位块(数量可由lpCount传出,包括对齐用的) const WORD* GetBaseRelocationBlock(const IMAGE_BASE_RELOCATION* lpBaseRelocation, LPDWORD lpCount = NULL) const; //解析某个基址重定位表后的某一项,返回的是高4位的值,低12位的值可由lpParam传出【任何时候均后可用】 static WORD ParseBaseRelocationBlock(WORD wBaseRelocationBlock, LPWORD lpParam = NULL); // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadDebug成功 public: //获取调试数据(数量可由lpDebugDirectoryNum传出) const IMAGE_DEBUG_DIRECTORY* GetDebugDirectory(LPDWORD lpDebugDirectoryNum = NULL) const; //获取第dwIndex项调试信息起始地址,未获取到返回NULL LPCVOID GetDebugInfoStart(DWORD dwIndex); // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadTLS成功 public: //获取线程局部存储表(如果是64位程序,返回的实际是const IMAGE_TLS_DIRECTORY64*) const IMAGE_TLS_DIRECTORY32* GetTLSDirectory() const; //获取线程局部存储表回调函数数组的指针(如果是64位程序,返回的实际是const ULONGLONG*)(数量可由lpCallbackNum传出) const DWORD* GetTLSCallback(LPDWORD lpCallbackNum = NULL) const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadLoadConfig成功 public: //获取加载配置表(如果是64位程序,返回的实际是const IMAGE_LOAD_CONFIG_DIRECTORY64*) const IMAGE_LOAD_CONFIG_DIRECTORY32* GetLoadConfigDirectory() const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadBoundImport成功 public: //获取绑定导入表(数量可由lpBoundImportNum传出) const IMAGE_BOUND_IMPORT_DESCRIPTOR* const* GetBoundImportDescriptor(LPDWORD lpBoundImportNum = NULL) const; //获取第iBoundImpoert个绑定导入表(数量可由lpRefNum传出) const IMAGE_BOUND_FORWARDER_REF* GetBoundImportForwarderRef(DWORD iBoundImport, LPDWORD lpRefNum = NULL) const; // 以下函数无特殊说明仅用于IMAGE_NT_SIGNATURE且ReadDelayImport成功 public: //获取延迟加载导入表(数量可由lpDelayImportNum传出) const IMAGE_DELAYLOAD_DESCRIPTOR* GetDelayImportDescriptor(LPDWORD lpDelayImportNum = NULL) const; /*--------------------------------------------------------------------------------------------------------------------*/ //其他私有成员略 };
注释部分已经详细说了各功能,主要操作如下:
1、调用Attach成员函数使类对象附加到一个PE文件
2、通过ReadXXX 读取需要的目录(包括导入表、导出表、资源表、基址重定位....)
3、调用相关处理函数获取相应信息(根据读取内容的不同而不同,具体参看注释)
4、将获得的数据做你想要的操作(如显示出来等)
5、ClearXXX释放资源(可选,对象析构时会自动调用)
6、Detach释放对该文件的关联(可选,对象析构时会自动调用)
目前基本数据目录中的大部分都可以获取,.Net部分(IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)还未实现,之后会继续完善
之后的链接中附有一个Demo演示如何使用该类,如仍有不清楚的朋友可以回复寻问我
最后发一个自己写的获取PE文件信息的软件,可以Dump出PE文件的各信息,该软件是用该PE解析类实现的,具体代码较多,初看并不易懂,所以在这不提供了国。
该软件我会附载之后的下载链接里,可以方便获取PE文件中各信息,由于精力有限,写的是控制台下的,有兴趣的朋友可以自己实现一个GUI版本的~
软件中,只需在控制台下输入PE文件路径,或者将文件拖拽进窗口(插入.lnk快捷方式也行),程序会将需要的信息输出来。
以下附上软件的一部分截图:
哈,啰嗦了这么多,接下来就留给各位去体验吧,其实PE文件没想像那么难~
相关资源下载地址:
(内含PE文件解析类源码文件、简单DEMO、以及自已实现的控制台PE文件查看器)
参考书籍:
《Windows PE权威指南》戚利
《加密与解密(第三版)》段钢
《软件加密技术内幕》看雪学院
《Windows环境下32位汇编语言程序设计(典葳版)》罗云彬
《加密与解密》吴强
《逆向工程核心原理》李承远
参考软件:
Stud_PE
LordPE
StudyPE+
eXeScope-ha
CFF Explorer
Resource Hacker
PEID
PEview
ExeinfoPe
OllyDbg
IDA Pro
参考源码:
PEDump
libpe-master
The Portable Executable File Format from Top to Bottom
PE文件格式官方文档:Microsoft PE and COFF Specification
在线PEDump工具:PEdump - dump your PE!
同时参考了CSDN、看雪学院、吾爱破解上等资料,在此一并感谢!
-
springMVC:为MultipartFilte配置了上传文件解析器,报错或不能使用
2018-08-01 17:44:57一、问题描述 为支持restful风格请求...目的是让MultipartFilter过滤器先将带文件上传的请求,进行解析。以便hiddenHttpMethodFilter可以取到”_method”参数,转化为相应的http动作。 既然multipartFilter要进行...一、问题描述
为支持restful风格请求,并且应对可能上传文件的情况,需要在配置hiddenHttpMethodFilter过滤器之前配置MultipartFilter。目的是让MultipartFilter过滤器先将带文件上传的请求,进行解析。以便hiddenHttpMethodFilter可以取到”_method”参数,转化为相应的http动作。
既然multipartFilter要进行上传文件的解析,那么必然需要MutipartResolver,那么问题发生了!二、报错:Unable to process parts as no multi-part configuration has been provided
配置如下
web.xml
<filter> <filter-name>MultipartFilter</filter-name> <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class> <init-param> <param-name>multipartResolverBeanName</param-name> <param-value>multipartResolver</param-value> </init-param> </filter>
springmvc.xml DispatcherServlert的上下文文件
我们使用了commons-fileupload-1.3.1.jar提供的CommonsMultipartResolver解析器<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize" value="20000000"/> <property name="defaultEncoding" value="utf-8"></property> </bean>
另外,还有一个multipartResolver需要介绍:
org.springframework.web.multipart.support.StandardServletMultipartResolverCommonsMultipartResolver:使用commons Fileupload来处理multipart请求,使用时需导入jar包。
StandardServletMultipartResolver:是基于Servlet3.0来处理multipart请求的,所以不需要引用其他jar包,但是必须使用支持Servlet3.0的容器才可以.原因:
如果你配置的multipartFilter的multipartResolver是CommonsMultipartResolver,即如上面springmvc.xml,
web.xml的配置,报这个错误的话,说明你配置的上传文件的解析器(CommonsMultipartResolver)根本,没有用到,而是使用这个上传文件的解析器(StandardServletMultipartResolver),而你又没有对这个解析器提供必要的配置信息,所以报错。三、解决问题
1、解决报错
给StandardServletMultipartResolver提供配置信息即可,(注:为何这样配置,原因见https://blog.csdn.net/gao_zhennan/article/details/81327268)
web.xml<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/applicationContext-web.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <!-- StandardServletMultipartResolvershu属性配置 --> <multipart-config> <max-file-size>20848820</max-file-size> <max-request-size>418018841</max-request-size> <file-size-threshold>1048576</file-size-threshold> </multipart-config> </servlet>
至此、报错的问题已经解决。但是为什么我们配置的上传文件的解析器没有用到呢?说来话长,我们源码中见。
2,解决未使用我们自己配置的上传文件的解析器(CommonsMultipartResolver)
MultipartFilter关键源码public class MultipartFilter extends OncePerRequestFilter { public static final String DEFAULT_MULTIPART_RESOLVER_BEAN_NAME = "filterMultipartResolver"; private String multipartResolverBeanName = DEFAULT_MULTIPART_RESOLVER_BEAN_NAME; private final MultipartResolver defaultMultipartResolver = new StandardServletMultipartResolver(); //将web.xml文件中为multipartFilter设置的参数(init-param)的属性值(param-value), //通过调用set方法设置进来,此时multipartResolverBeanName=multipartResolver public void setMultipartResolverBeanName(String multipartResolverBeanName) { this.multipartResolverBeanName = multipartResolverBeanName; } protected String getMultipartResolverBeanName() { return this.multipartResolverBeanName; } protected MultipartResolver lookupMultipartResolver() {//关键方法:用来查找上传文件的解析器 WebApplicationContext wac = WebApplicationContextUtils. getWebApplicationContext(getServletContext()); // 1.WebApplicationContext 是spring的上下文对象,在ContextLoaderListener加载spring的配置文件后,将生成的对应的WebApplicationContext,先放在了web.xml的上下文对象中ServletContext String beanName = getMultipartResolverBeanName(); // 2.上面有这个方法,返回值为this.multipartResolverBeanName,即"multipartResolver" if (wac != null && wac.containsBean(beanName)) { // 3.1只要监听器ContextLoaderListener,加载了spirng的配置文件wac 就不会是null, // 现在关键的是:ContextLoaderListener加载的配置文件中是否配置了这个bean(id="multipartResolver") return wac.getBean(beanName, MultipartResolver.class); } else { //3.2如过ContextLoaderListener加载的配置文件中没有这个bean,则与之 //对应的WebApplicationContext对象中也不包含这个bean, //于是wac.containsBean(beanName) 为false。 //返回默认的解析器"StandardServletMultipartResolver" return this.defaultMultipartResolver; } }
有点抽象,说的再多不如去做下。在前端页面发送了一个带文件上传控件的表单,看MutilFilter是否使用我配置的文件上传的解析器(CommonsMultipartResolver)。
wac.containsBean(beanName) beanName=”multipartResolver” 为false。说明你在spring的上下文中没有配置id=”multipartResolver”。奇怪了,我明明在springmvc.xml中配置了id=”multipartResolver”.为什么在spring对应的上下文对象中找不到呢?这里就要牵扯到新的概念了。springmvc.xml是由DispatcherServlet加载的,然后生成了springmvc的上下文对象,称为子容器。 ContextLoaderListener加载的配置文件,生成的spring的上下文对象,称为父容器。 子容器可以使用父容器中定义的bean,反之则不行。 如上multipartResovler配置在springmvc.xnl中,即对应的bean在子容器中,而WebApplicationContext.containsBean()在父容器中是查找不到这个bean的
问题解决
1.新建一个applicationContext.xml(名字任意取),
2.将multipartResovler配置在其中。
3.重要的是要通过ContextLoaderListener来加载此文件,这样这个bean就在spring的容器里了,然后WebApplicationContext.containsBean()为true,就会使用你配置的解析器,而不是使用默认的了。
最后放张图spring和spirngmvc父子容器介绍
(转发自 https://blog.csdn.net/jml1437710575/article/details/52020936)在百度中别人的帖子中看到一段应该是官方的原文解释,我摘抄过来并粗糙的直译一下:
Spring lets you define multiple contexts in a parent-child hierarchy.
spring允许你定义多个上下文在父子继承关系中The applicationContext.xml defines the beans for the “root webapp context”, i.e. the context associated with the webapp.
applicationContext.xml文件是为了”根webapp应用上下文”定义bean, 也就是说它的上下文是和webapp想关联的The spring-servlet.xml (or whatever else you call it) defines the beans for one servlet’s app context. There can be many of these in a webapp,
spring-servlet.xml文件(或是其他的你习惯的称呼)是为了一个servlet应用上下文呢定义bean. 在一个webapp中可以有多个此配置文件,one per Spring servlet (e.g. spring1-servlet.xml for servlet spring1, spring2-servlet.xml for servlet spring2).
每一个spring的servlelt(例如: 名为spring1的servlet拥有配置文件spring1-servlet.xml, 名为spring2的servlet拥有配置文件spring2-servlet.xml).Beans in spring-servlet.xml can reference beans in applicationContext.xml, but not vice versa.
在spring-servlet.xml中定义的bean可以直接引用在applicationContext.xml中定义的bean, 但是反过来不可以.All Spring MVC controllers must go in the spring-servlet.xml context.
所有springmvc的Controller必须在spring-servlet.xml对应的上下文中运行.In most simple cases, the applicationContext.xml context is unnecessary. It is generally used to contain beans that are shared between all servlets
在大多数简单的情况下, applicationContext.xml对应的上下文并不必须. 它通常用来包含那些bean用来在webapp中所有servlet之间共享.in a webapp. If you only have one servlet, then there’s not really much point, unless you have a specific use for it.
如果你只有一个servlet, 那么实际没有什么必要定义applicationContext.xml, 除非你有特别应用. -
全网最详细完备的class类文件结构解析
2021-05-21 23:54:03写在前面 本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和文献引用请见...4. 类索引、父类索引与接口索引集合 5. 字段表写在前面
本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!
本专栏目录结构和文献引用请见100个问题搞定Java虚拟机
解答
Class文件是一组以8位字节为基础单位的二进制流,不同的数据项目严格按照顺序紧凑地排列在Class文件之中,中间没有任何空隙存在。 这些数据项目由无符号数和表来存储数据,按照顺序依次是: 1. 魔数和Class文件的版本 2. 常量池 3. 访问标志 4. 类索引、父类索引与接口索引集合 5. 字段表集合 6. 方法表集合 7. 属性表集合 Java代码之所以能够一直保持良好的向后兼容性,就是因为class类文件结构一直比较稳定。
补充
可能很多人觉得了解学习 class 类文件结构对于开发 Java 代码没有什么用处,深度学习了本文,下面的问题你就能自己回答了。
- Java为什么能一直保持良好的向后兼容性?
- Java虚拟机是怎样处理异常的?
- Java代码抛出异常堆栈的时候是如何打印出代码行号的?
- Java代码抛出异常堆栈的时候是怎样识别文件名称的?
- IDE调试的时候Java程序是如何识别断点的?
- IDE调试的时候是如何识别方法参数名称的?
- 类变量和实例变量是什么时候赋值的?
- Java中泛型是如何实现的?泛型信息是如何保存的?
- Java模块化功能是如何实现的?
无符号数
无符号数是基本的数据类型,u1、u2、u4、u8分别表示1个字节、2个字节、4 个字节和8个字节的无符号数。
无符号数可以用来表示数字、索引引用、数量值或者按照UTF-8编码构成字符串。
表
表用于描述有层次关系的复合结构的数据,由多个无符号数或者其他表构成。
所有表都习惯性地以"_info”结尾。
容器计数器
无论是无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用个前置的容量计数器加若干个连续的数据项的形式, 这时称这一系列连续的某一类型的数据为某一类型的集合。
魔数(Magic Number)
每个Class文件的头4个字节称为魔数,即:OXCAFEBABE(咖啡宝贝)
作用
确定这个文件是否是一个合法的Class文件。
因为文件扩展名可以随意地改动,所以使用魔数而不是扩展名来进行识别class文件更加的可靠。
Class文件的版本
紧接着魔数的4个字节存储的是Class文件的版本号:
5、6个字节是次版本号
7、8个字节是主版本号
Java的版本号是从45开始的,JDK1.1之后的每个JDK大版本发布主版本号向上加1。
可以推导出 JDK8 的版本号是 52.0
JDK1.2~JDK12之间次版本号都为0。
JDK12以后考虑到一些复杂的特性需要公测,重新启用了次版本号。
高版本的JDK能向下兼容以前版本的Class文件,但不能运行以后版本的 Class文件,即使文件格式并未发生任何变化,虚拟机也必须拒绝执行超过其版本号的Class文件。
常量池(Constant Pool)
紧接着主次版本号之后的是常量池入口,常量池可以理解为Class文件的资源仓库。
常量池是Class文件结构中与其他数据项目关联最多的数据类型,通常也是占用 Class文件空间最大的数据项目之一,同时它还是在 Class文件中第一个出现的表类型数据项目。
由于常量池中常量的数量是不固定的,所以在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值。
与Java中语言习惯不一样的是,这个容量计数是从1而不是0开始的。
常量池中主要存放两大类常量:字面量和符号引用
字面量(Literal)
字面量类似于Java语言里面的常量,包括文本字符串、声明为final的常量值等。
符号引用(Symbolic References)
符号引用包括了下面6类常量:
- 被模块导出或者开放的包(JDK9+)
- 类和接口的全限定名
- 字段的名称和描述符
- 方法的名称和描述符
- 方法句柄和方法类型
- 动态调用点和动态常量
关于 5、6 请见我的另一篇博客——invokedynamic是如何实现的?
Java代码需要在虚拟机加载Class文件的时候进行动态连接。
当虚拟机运行时,需要从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址之中。
访问标志(Access Flags)
在常量池结束之后,紧接着的两个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息,包括:
- 这个Class是类还是接口;
- 是否定义为public类型;
- 是否定义为abstract类型;
- 如果是类的话,是否被声明为final等
类索引、父类索引与接口索引集合(this class,super class and interfaces)
类索引和父类索引都是一个u2类型的数据,而接口索引集合是一组u2类型的数据的集合。
Class文件中由这三项数据来确定这个类的继承关系。
类索引
类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。
父类索引与继承
由于Java语言不允许多重继承,所以父类索引只有一个,除了java.lang.Object之外,所有的Java类都有父类,因此除了java.lang.Object外,所有Java类的父类索引都不为0。
接口索引集合
接口索引集合就用来描述这个类实现了哪些接口,被实现的接口将按implements语句(如果这个类本身是一个接口,则应当是extends语句)后的接口顺序从左到右排列在接口索引集合中。
字段表集合(Field Info)
字段表用于描述接口或者类中声明的变量。
字段包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。(方法内部的局部变量存储在栈帧的局部变量表内部。)
在Java中描述一个字段可以包括的信息有:
- 字段的作用域(public、 private、 protected修饰符)
- 是实例变量还是类变量(static修饰符)
- 可变性(final)
- 并发可见性(volatile修饰符,是否强制从主内存读写)
- 可否被序列化(transient修饰符)
- 字段数据类型(基本类型、对象、数组)
- 字段名称
上述这些信息中,每个修饰符都是布尔值,要么有某个修饰符,要么没有,所以很适合使用标志位来表示。
而字段叫什么名字、字段被定义为什么数据类型,这些都是无法固定的,只能引用常量池中的常量来描述。
方法表集合
方法表的结构类似于字段表,依次包括了
- 访问标志
- 名称索引
- 描述符索引
- 属性表集合
方法表存储的是方法的元数据信息,真正的代码存储在方法属性表中的 Code 属性里面。
属性表集合
Class 文件、字段表、方法表都可以携带自己的属性表集合,用来描述某些场景专有的信息。
《Java虚拟机规范》不再要求各个属性表具有严格顺序,只要不与已有属性名重复,任何人实现的编译器都可以向属性表中写入自己定义的属性信息,
Java虚拟机运行时会忽略掉它不认识的属性。
属性名称 使用位置 含义 Code 方法表 Java代码编译成的字节码指令 Exceptions 方法表 方法抛出的异常列表 LineNumberTable Code属性 Java源码的行号与字节码指令的对应关系 LocalVariableTable Code属性 方法的局部变量描述 SourceFile 类文件 记录源文件名称 ConstantValue 字段表 由 final 关键字定义的常量值 InnerClasses 类文件 内部类列表 Signature(JDK5+) 类、方法表、字段表 用于支持泛型情况下的方法签名 BootstrapMethods(JDK7+) 类文件 用于保存 invokedynamic 指令引用的引导方法限定符 MethodsParameters(JDK8+) 方法表 支持将方法名称编译进 Class 文件中,可以运行时获取 Module/ModulePackages/ModuleMainClass(JDK9+) 类 支持模块化相关功能 Code
Java程序方法体中的代码经过 Javac 编译器处理后,最终变为字节码指令存储在 Code 属性内。
Code属性出现在方法表的属性集合之中,但并非所有的方法表都必须存在这个属性, 譬如接口或者抽象类中的方法就不存在Code属性,
Code属性是 Class 文件中最重要的一个属性,
如果把一个Java程序中的信息分为代码(code,方法体里面的Java代码)和元数据(Metadata,包括类、字段、方法定义及其他信息)两部分,
那么在整个 Class文件中,Code属性用于描述代码,所有的其他数据项目都用于描述元数据。
异常表(可选)
在字节码指令之后的是这个方法的显式异常处理表(下文简称异常表)集合,异常表对于Code属性来说并不是必须存在的
关于异常表的详细内容请参考我的另一篇博客——JVM是如何处理异常的?
Exceptions
这里的Exceptions属性是在方法表中与Code属性平级的一项属性,上面的异常表是 Code 属性里面的内容。
Exceptions属性的作用是列举出方法中可能抛出的受检异常(Checked Exceptions),也就是方法描述时在throws关键字后面列举的异常。
LineNumberTable(可选)
LineNumberTable属性用于描述Java源码行号与字节码行号(字节码的偏移量)之间的对应关系。
默认会生成到 Class文件之中,可以在Javac中分别使用-g:none 或-g:lines选项来取消或要求生成这项信息。
如果选择不生成LineNumberTable属性,对程序运行产生的最主要的影响就是当抛出异常时,堆栈中将不会显示出错的行号,
并且在调试程序的时候,也无法按照源码行来设置断点。
LocalVariableTable属性(可选)
LocalVariableTable属性用于描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系,
默认会生成到 Class文件之中,可以在 Javac 中分别使用-g.none或-g:vars选项来取消或要求生成这项信息。
如果没有生成这项属性,最大的影响就是当其他人引用这个方法时,所有的参数名称都将会丢失,IDE将会使用诸如arg0、arg1之类的占位符代替原有的参数名,
这对程序运行没有影响,但是会对代码编写带来较大不便,而且在调试期间无法根据参数名称从上下文中获得参数值。
SourceFile属性(可选)
SourceFile属性用于记录生成这个Class文件的源码文件名称。
可以分别使用Javac的-g:none或-g:source选项来关闭或要求生成这项信息。
在Java中,对于大多数的类来说,类名和文件名是一致的,但是有一些特殊情况(如内部类)例外。
如果不生成这项属性,当抛出异常时,堆栈中将不会显示出错代码所属的文件名。
ConstantValue属性
ConstantValue属性的作用是通知虚拟机自动为静态变量赋值。
只有被static关键字修饰的变量(类变量)才可以使用这项属性。
实例变量什么时候进行初始化?
对于实例变量的赋值是在实例构造器方法中进行的;
类变量什么时候初始化?
对于类变量,则有两种方式可以选择
- 在类构造器方法中
- 使用ConstantValue属性
目前Oracle实现的Java编译器的选择是
- 如果同时使用final和static来修饰一个变量(按照习惯,这里称“常量”更贴切),并且这个变量的数据类型是基本类型或者java.lang.String的话,就生成 ConstantValue 属性来进行初始化,
- 如果这个变量没有被final修饰,或者并非基本类型及字符串,则将会选择在方法中进行初始化。
InnerClasses属性
InnerClasses 属性用于记录内部类与宿主类之间的关联。
如果一个类中定义了内部类,那编译器将会为它以及它所包含的内部类生成 InnerClasses属性。
Signature属性
Signature属性在JDK1.5发布后增加到了 Class 文件规范之中,它是一个可选的定长属性,可以出现于类、属性表和方法表结构的属性表中。
在JDK1.5中大幅增强了Java语言的语法,在此之后,任何类、接口、初始化方法或成员的泛型签名如果包含了类型变量(Type Variables)或参数化类型(Parameterized Types), 则Signature属性会为它记录泛型签名信息。
擦除法实现泛型
之所以要专门使用这样一个属性去记录泛型类型,是因为Java语言的泛型采用的是擦除法实现的伪泛型,
在字节码(Code属性)中,泛型信息编译(类型变量、参数化类型)之后都通通被擦除掉。
擦除法的好处与坏处
使用擦除法的好处是实现简单(主要修改Javac编译器,虚拟机内部只做了很少的改动)、非常容易实现Backport(即将一个软件的补丁应用到比此补丁所对应的版本更老的版本的行为),运行期也能够节省一些类型所占的内存空间。
但坏处是运行期就无法像C#等有真泛型支持的语言那样,将泛型类型与用户定义的普通类型同等对待,例如运行期做反射时无法获得到泛型信息。
Signature属性就是为了弥补这个缺陷而增设的,现在Java的反射API能够获取泛型类型,最终的数据来源也就是这个属性。
BootstrapMethods 属性
BootstrapMethods属性在JDK1.7发布后增加到了 Class文件规范之中,它是一个复杂的变长属性,位于类文件的属性表中。
这个属性用于保存 invokedynamic 指令引用的引导方法限定符。
MethodParameters属性
作用是记录方法的各个形参名称和信息。
编译器可以(编译时加上-parameters 参数)将方法名称写入 Class 文件。
MethodParameters VS LocalVariableTable
LocalVariableTable是Code属性的子属性(抽象方法和接口方法没有方法体就没有对应的 Code属性)。
JDK8 以前要获取方法名称(比如 IDE 的代码提示)只能通过 JavaDoc 得到。
MethodParameters是方法表的属性,和 Code 平级。
模块化相关属性
JDK9的最重要的功能是提供 Java 的模块化功能,因为模块描述文件(module-info.java)最终要编译成一个独立的 Class 文件来存储的。
所以 Class 文件格式也扩展了 Module/ModulePackages/ModuleMainClass 三个属性用于支持 Java 模块化的相关功能。
-
springMVC4(13)视图解析器分类详解
2016-04-06 09:17:51在 《springMVC4(7)...下一步,视图对象往往会对模型进一步渲染,再由视图解析器进一步解析并向前端发出响应。在下面,我们详细介绍视图和视图解析器的各种分类。 在View接口中,定义了一个核心方法是: void rend -
Android中XML的三种解析器分析、实战
2020-05-28 16:13:24本文分析了Android中,可使用的三种XML解析器,并对它们的实现逻辑及优缺点进行了分析和对比。 我们在实战部分,分别用三种解析器实现了Demo中XML文件的解析,代码注释详细的介绍了整个过程。 -
Java解析XML文件的方式
2020-01-30 18:36:06在项目里,我们往往会把一些配置信息放到xml文件里,或者各部门间会通过xml文件来交换业务数据,所以有时候我们会遇到“解析xml文件”的需求。一般来讲,有基于DOM树和SAX的两种解析xml文件的方式,在这部分里,将... -
SpringMVC-视图和视图解析器
2019-05-06 22:56:46视图(View)和视图解析器(ViewResolver)的工作流程: 当请求处理方法处理完请求之后,会返回String、ModelAndView、或View对象,如return “success”,但这三种返回值最终都会被SpringMVC统一转化为ModelAndView对象... -
PE文件解析-文件头与整体介绍
2019-01-03 20:58:37一、PE的基本概念 PE(Portable Execute)文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,...Windows加载器(又称PE加载器)遍历PE文件并决定文件的哪一部分被映射,这种映射方式是将文件较高的偏移... -
视图解析器
2018-08-20 10:13:23·SpringMVC 使用ViewResource 进行视图解析,在浏览器中渲染模型 ·ViewResolver 能够解析JSP、Velocity 模版和XSLT 等多种视图 ·处理视图最重要的两个接口: ·ViewResolver接口在视图...常见的视图解析器... -
springMVC4视图解析器分类详解
2017-03-29 17:36:57在 《springMVC4(7)...下一步,视图对象往往会对模型进一步渲染,再由视图解析器进一步解析并向前端发出响应。在下面,我们详细介绍视图和视图解析器的各种分类。 在View接口中,定义了一个核心方法是: void r -
SpringMVC 视图解析器
2019-04-22 16:57:241.视图解析器 会 根据 把控制器返回的逻辑视图名 确定渲染模型的视图文件的物理位置。 Spring MVC的一个重要特性:将控制器中处理请求的逻辑 和 视图中渲染实现 解耦。 控制器方法和视图实现 只会在模型内容上保持... -
关于使用JAVA进行MIB文件解析
2018-11-09 11:40:07最近工作上有功能需求解析MIB文件,在网上找了一圈之后发现都是不全的,很多论坛的提问及回答都是很多年前的,最后经过摸索找到了完整的解析方法,因此做个记录,也希望给其他需要的人一个帮助。 以下是我的java... -
spring boot中配置jsp视图解析器
2018-06-11 22:03:09启动器@SpringBootApplication public class ApplicationRun { public static void main(String[] args) { SpringApplication.run(ApplicationRun.class, args); } }1234567配置类@Configuration @Enable... -
深入理解Java类加载器(1):Java类加载原理解析
2017-05-21 18:26:292 Java虚拟机类加载器结构简述 2.1 JVM三种预定义类型类加载器 2.2 类加载双亲委派机制介绍和分析 2.3 类加载双亲委派示例 3 java程序动态扩展方式 3.1 调用java.lang.Class.forName(…)加载类 3.2 用户自定义... -
python configparser配置文件解析器使用详解
2018-09-27 21:38:53[原文引用1] 原文引用2(https://xin053.github.io/2016/07/18/configparser配置文件解析器使用详解/) python2下该模块名为ConfigParser,到3才改为configparser,可以看官方ConfigParser模块的说明 ConfigParse 官方... -
深入理解Java类加载器(一):Java类加载原理解析
2017-05-15 20:47:44每个开发人员对java.lang...本文简述了JVM三种预定义类加载器,即启动类加载器、扩展类加载器和系统类加载器,并介绍和分析它们之间的关系和类加载所采用的双亲委派机制,给出并分析了与Java类加载原理相关的若干问题。 -
解析XML文件(一)
2018-11-08 17:58:58在进行XML文件的解析之前,我们简单介绍下什么是XML,以及XML在企业中有哪些作用。(本文建立在不使用数据库的前提之下,如果你正在使用数据库,或许并不需要学习本文) 什么是XML? XML指可拓展标记语言 XML是... -
Intel HEX文件解析
2016-04-05 17:22:50最近有一个需求就是为Arduino开发板做一个基于蓝牙的无线烧录程序。目前的Arduino程序都是通过USB线连接到电脑的主机上,实际的传输过程是基于USB协议的,这个过程还是比较麻烦的...每个Arduino源程序,即sketch文件, -
Spring MVC(四)——配置视图解析器
2019-07-29 16:53:40Spring MVC中所有的控制器(controller)方法...在Spring中,视图是由一个视图名标识,并且在视图解析器中渲染。 一下是一些spring提供的视图解析器: 视图解析器 描述 AbstractCachingViewRes... -
自己写一个docx格式的解析器
2018-12-24 10:35:25众所周知,docx格式是国际软件巨头-微软为其自家产品Word所定义的一个文件格式,当然docx这种格式已经有很多很多的解析库可用了,但是你有没有想过自己一个docx的解析器呢? 首先,我们先做一个小小的实验,准备一... -
配置SpringMVC中的视图解析器
2018-09-20 10:50:15视图解析器的作用: 就是当 DispatcherServlet将ModelAndView传递给视图解析器的时候,将ModelAndView数据填充到相应的视图中,然后返回一个带有数据的视图给DispatcherServlet. 视图解析其中有个抽象类: ... -
java工具之解析yaml文件
2020-02-24 20:22:01工具使用背景很多配置项都是使用yaml的格式进行配置的, 按一定的格式进行缩进, 一眼看上去,清晰明了.如Springboot工程下图所示:如:k8s的Deploy文件:本次写这个yam... -
项目——PE解析器(MFC)
2020-07-06 02:27:32文件对话框 CFileDialog dlgFile(TRUE, \ NULL, \ NULL, \ OFN_HIDEREADONLY, \ _T("Data Files (*exe;*.sys;*.dll)|*exe; *.sys; *.dll|All Files (*.*)|*.*||"), \ /*_T("Describe Files (*.exe)|*.... -
XML文件解析及C#基本实现
2018-10-21 20:24:21XML文件概述 XML全称Extensible Markup Language,可扩展标记语言,与超文本标记语言(HTML,HyperText Markup Language)同属于标准通用标记语言的子集。XML被设计用来传输和存储数据,使文档具有结构性;而HTML被... -
破解 --- apk文件解析
2021-06-03 20:47:27apk是类似Symbian Sis或Sisx的文件格式。通过将APK文件直接传到Android模拟器或Android手机中执行即可安装。 1.apk文件目录 asset 资源文件 lib ARM X86 so MET-TNF 签名文件夹 CERT.RSA CERT.SF MANIFEST.MF res... -
Qt如何解析Json文件
2021-07-16 20:52:19Qt中内置了一个QJsonDocument类用来处理json文件。并提供一些类来处理json。 类 功能 QJsonArray 封装 JSON数组 QJsonDocument 读写 JSON 文档 QJsonObject 封装 JSON 对象 QJsonObject::... -
Springboot2.x配置thymeleaf和jsp双视图解析器
2019-05-10 16:16:24* @Description: 将自定义tml视图解析器添加到模板引擎并主持到ioc */ @Bean public SpringTemplateEngine templateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); template...