本文记录一些spring开发过程中的小细节。
1、Spring2.5中引入了@Autowired这个注释,它可以将类成员变量、方法、构造函数进行标注,来完成自动装配的工作。也就是说,标注了@Autowiredd类的bean里面再也不需要其他属性了,@Autowired就会把需要的东西自动转配好的。
2、Spring是通过一个BeanPostProcessor对@Autowired注释进行解析的,所以如果想让@Autowired注释起作用,必须事先在spring容器中声明AutowiredAnnotationBeanPostProcessor这个bean,让系统认识@Autowired,才能让@Autowired工作起来。
3、报错信息:Spring 容器抛出BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。
原因:在默认情况下使用 @Autowired 注释进行bean的自动装配时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。
当找不到一个匹配的 Bean 时,就会抛出这个异常。
解决方法:在需要自动注入该类 的Bean 的地方使用 @Autowired(required = false)(在java代码中,不是配置文件中)。当不能确定 Spring 容器中一定拥有某个类的 Bean 时,这样的写法就等于告诉 Spring:在找不到匹配的 Bean 时,也不报错。
4、报错信息:Spring 容器抛出BeanCreationException 异常。
原因:与3中的原因正好相反的情况。Spring 容器中拥有了多个候选 的Bean,Spring 容器在启动时不知道装入哪一个bean,所以也会抛出 BeanCreationException 异常。
解决方法:通过 @Qualifier("XXX") 注释(在java代码写参数的地方,不是配置文件中),指定注入 Bean 的名称(代码中的XXX),这样歧义就消除了。
5、由3、4中的小知识可以看出,@Autowired 和@Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。@Autowired 可以对成员变量、方法以及构造函数进行注释,而@Qualifier 的标注对象是成员变量、方法入参、构造函数入参。正是由于注释对象的不同,所以 Spring 没有将 @Autowired 和@Qualifier 统一成一个注释类。
6、Sping的声明式事务,就是在配置文件中采用配置的方式对事务进行管理,不用自己编写代码,全靠配置就能完成事务控制。Spring中的AOP就是完成事务管理工作的(还有日志管理工作、安全管理工作)。
7、 乱码处理
1). post乱码
在web.xml添加post乱码filter:CharacterEncodingFilter
2). 对于get请求中文参数出现乱码解决方法有两个:
a. 修改tomcat配置文件,添加编码与工程编码一致,如下:
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
b. 对参数进行重新编码:
String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。
8、上传图片
1). 在页面form中提交enctype="multipart/form-data"的数据时,需要springMVC对multipart类型的数据进行解析。
2). 在springmvc.xml中配置multipart类型解析器。
3). 方法中使用:MultipartFile attach (单个文件上传) 或者 MultipartFile[] attachs (多个文件上传)。
9、异常处理
springMVC提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。系统遇到异常,在程序中手动抛出,dao抛给service、service给controller、controller抛给前端控制器,前端控制器调用全局异常处理器。
10、 数据回显
1). @ModelAttribute还可以将方法的返回值传到页面:在方法上加注解@ModelAttribute
2). 使用最简单方法使用model,可以不用@ModelAttribute:model.addAttribute("id", id);
3). springMVC默认对pojo数据进行回显。pojo数据传入controller方法后,springMVC自动将pojo数据放到request域,key等于pojo类型(首字母小写)
4). public String testParam(PrintWriter out, @RequestParam("username") String username) { //out直接输出}
11、spring 校验
1). 项目中,通常使用较多是前端的校验,比如页面中js校验。对于安全要求较高的项目,建议在服务端进行校验。
2). springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。校验思路:页面提交请求的参数,请求到controller方法中,使用validation进行校验。如果校验出错,将错误信息展示到页面。
12、 集合类型绑定
1). 数组绑定:
controller方法参数使用:(Integer[] itemId)
页面统一使用:itemId 作为name
2). list绑定:
pojo属性名为:itemsList
页面:itemsList[index].属性名
3). map 绑定:
pojo属性名为:Map<String, Object> itemInfo = new HashMap<String, Object>();
页面: <td>姓名:<inputtype="text"name="itemInfo['name']"/>
13、 Json处理
1). 加载json转换的jar包:springmvc中使用jackson的包进行json转换(@requestBody和@responseBody使用下边的包进行json转)
2). 配置json转换器。在注解适配器RequestMappingHandlerAdapter中加入messageConverters。如果使用<mvc:annotation-driven/> 则会自动加入。
3). ajax代码:
4). Controller (ResponseBody、RequestBody)
5). 注意ajax中contentType如果不设置为json类型,则传的参数为key/value类型。上面设置后,传的是json类型。
14、 拦截器:
1). 定义拦截器,实现HandlerInterceptor接口。接口中提供三个方法。
a. preHandle :进入 Handler方法之前执行,用于身份认证、身份授权,比如身份认证,如果认证通过表示当前用户没有登陆,需要此方法拦截不再向下执行
b. postHandle:进入Handler方法之后,返回modelAndView之前执行,应用场景从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
c. afterCompletion:执行Handler完成执行此方法,应用场景:统一异常处理,统一日志处理
2). 配置拦截器:
a. 针对HandlerMapping配置(不推荐):springmvc拦截器针对HandlerMapping进行拦截设置,如果在某个HandlerMapping中配置拦截,经过该 HandlerMapping映射成功的handler最终使用该拦截器。 (一般不推荐使用)
b. 类似全局的拦截器:springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中。多省事儿。
15、 如何启用注解:
<context:annotation-config/>
如果使用<context:component-scan base-package="com.tgb.web.controller.annotation"> </context:component-scan> 则上面内容可以省略,推荐使用<mvc:annotation-driven/>代替注解映射器和注解适配器配置。
16、默认情况下,web.xml文件将保存Web应用程序的WebContent/WEB-INF目录。在名为HelloWeb DispatcherServlet初始化时,框架将尝试从位于应用程序的WebContent/WEB-INF目录中的名为[servlet-name]-servlet.xml的文件加载应用程序上下文。在这个示例中,使用的文件将是HelloWeb-servlet.xml。
接下来,<servlet-mapping>标记指示哪些URL将由DispatcherServlet处理。 这里所有以.jsp结尾的HTTP请求都将由HelloWeb DispatcherServlet处理。
如果不想使用默认文件名为[servlet-name]-servlet.xml和默认位置为WebContent/WEB-INF,可以通过在web.xml文件中添加servlet侦听器ContextLoaderListener来自定义此文件名和位置。
17、web.xml 是用来初始化配置信息的,这些配置信息的加载顺序如下:context-param > listener > fileter > servlet。
18、DispatcherServlet应用的其实就是一个"前端控制器"的设计模式(其他很多优秀的web框架也都使用了这个设计模式):
①请求驱动;
②所有设计都围绕着一个中央Servlet来展开,它负责把所有请求分发到控制器;
③同时提供其他web应用开发所需要的功能。
19、WebApplicationContext继承自ApplicationContext,它提供了一些web应用经常需要用到的特性。它与普通的ApplicationContext不同的地方在于,它支持主题的解析,并且知道它关联到的是哪个servlet(它持有一个该ServletContext的引用)。
20、HandlerExceptionResolver和web.xml中配置的error-page,两者会有冲突吗?
①如果resolveException异常返回了ModelAndView的话,那就会优先根据返回值中的页面来显示的。不过,resolveException也可以返回null,此时则展示web.xml中的error-page的500状态码配置的页面。
②那么,当web.xml中有相应的error-page配置,在实现resolveException方法的时候就可以选择返回null了,反正会展示web.xml中的error-page的500状态码配置的页面。
21、Spring支持三种依赖注入方式,分别是属性(Setter方法)注入,构造注入和接口注入。在Spring中,那些组成应用的主体,即由Spring IOC容器所管理的对象被称之为Bean。
22、Spring的IOC容器通过反射的机制实例化Bean并建立Bean之间的依赖关系。
23、Bean就是由Spring IOC容器初始化、装配及被管理的对象。获取Bean对象的过程,首先通过Resource加载配置文件并启动IOC容器,然后通过getBean方法获取bean对象,就可以调用他的方法。
24、Spring Bean的作用域:
- Singleton:Spring IOC容器中只有一个共享的Bean实例,一般都是Singleton作用域。
- Prototype:每一个请求,会产生一个新的Bean实例。
- Request:每一次http请求会产生一个新的Bean实例。
25、AOP就是纵向的编程,如业务1和业务2都需要一个共同的操作,与其往每个业务中都添加同样的代码,不如写一遍代码,让两个业务共同使用这段代码。这样就提高了代码的复用性,也实现了与业务的解耦。在日常有订单管理、商品管理、资金管理、库存管理等业务,都会需要到类似日志记录、事务控制、权限控制、性能统计、异常处理及事务处理等功能。AOP把所有共有代码全部抽取出来,放置到某个地方集中管理,然后在具体运行时,再由容器动态织入这些共有代码。
26、Spring AOP应用场景
性能检测,访问控制,日志管理,事务等。
默认的策略是如果目标类实现接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理。