spring book
spring源码下载地址:
https://github.com/spring-projects
springBean <bean id="user" class="..."/> 默认是单例的.
如果要改成多例的则<bean id="user" class="..." singleton="false"/>
第个servlet用http请求后打印的hashcode都是一致的.
public void doPost(HttpServletRequest request, HttpServletResponse response) { System.out.println(this); }
2次请求打印一致
spring web.xml 难点配置总结
spring容器和springMVC容器的区别
本小节完全引用自: Spring和springmvc父子容器注解扫描问题详解--https://www.cnblogs.com/Prozhu/p/6709320.html
Spring和springmvc父子容器注解扫描问题详解
一、Spring容器和springmvc容器的关系如下图所示:

Spring和springmvc和作为两个独立的容器,会把扫描到的注解对象分别放到两个不同的容器中,
Springmvc容器是spring容器的一部分,他们访问对象的范围如下所示:
- springmvc子容器可以访问spring父容器中的对象
- spring父容器不能访问springmvc子容器中的对象
***在实际应用中的实例***
一般情况下,一个spring / springmvc / mybatis 组合的框架中,会存在以下几个配置文件:
applicationContext-service.xml 文件
<!-- 配置service层的组件扫描器 --> <context:component-scan base-package="com.prozhu.service"></context:component-scan>
说明:在这个里面存在着一个spring的注解扫描器。用来扫描@Service的注解
Springmvc.xml 文件
<!-- 配置Controller扫描器 --> <context:component-scan base-package="com.prozhu.controller" />
说明:这个里面存在着springmvc的注解扫描器,专门用来扫描@Controller的注解
然后呢?有点同学可能会想,我能不能合并成一个注解扫描器,来完成对象注入的问题?将配置文件中的注解扫描器更改为如下配置:
在applicationContext-service.xml文件中进行全局扫描的配置:
而在springmvc中不配置注解扫描器
<!-- 配置spring的注解扫描器 --> <context:component-scan base-package="com.prozhu" />
说明:用这个扫描器分别扫描service层和controller层的注解:@Service /@Controller / @Autowired
当一旦采用这种方式之后,spring会将扫描的对象都会存放到spring的容器,而不会放到springmvc子容器中,当访问项目的时候,
springmvc找不到处理器映射器,和其对应的Controller,进而报404错误!
不用spring容器,只用springmvc容器行不行呢?
答案:是可以的,在这个里面可以同时扫描Controller层、service层、dao层的注解。
在springmvc 和 spring 都有注解扫描的前提下,能不能将事务配置在Controller层?
答案:是不能的,因为事务管理器是配置在spring容器中的,如果将事务配置在Controller层的话,spring容器就访问不了springmvc子容器,
进而无法访问到事务对象。进而导致事务失效。
spring md5加密
org.springframework.util.DigestUtils.md5DigestAsHex(str.getBytes())
遇见异常
异常1: 事务不起作用
以上链接强调要使用Spring的SessionFactory的getCurrentSession的方法创建Session,
而不是通过Spring的SessionFactory的OpenSession的方法创建Session,因为OpenSession用的是另外一个线程,不受管控。
Spring中事务配置以及事务不起作用可能出现的问题--https://www.cnblogs.com/morewindows0/p/8270765.html
以上链接强调Spring事务配置不起作用可能出现的问题:
1.是否是数据库引擎设置不对造成的【笔者就遇到了这个问题,由于笔者使用的是mysql数据,但是在创建表的时候引擎默认(mysql中引擎默认为MyISAM,是不支持事务操作的),需要修改为InnoDB,就可以支持事务操作了】
2.入口函数必须是public,否则事务不起作用。这一点由Spring的AOP特性决定的。
@mark 2018年11月15号 , bobo自己因为在service类的@Transactional捕获了事务再抛出事务,并并并并并用finally导致事务已经变味了,于是事务回滚不起作用,当初一直没怀疑到这个点上,血的教训,以后异常就该直接抛,不要捕来捕去的. 因为finally一定会执行,所以本来抛出的异常不会再抛出了
异常2: BeanFactory not initialized or already closed
spring的项目中有时候会报错:java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
原因:spring初始化bean对象出错;
1)xml的bean的id 有重复;
2)如果是注解配置:可能是注解的名称有重复:
只需要将重复的bean 的id和重复的注解改了就行了;
异常3: No qualifying bean of type [com.abc.www.dao.itf.HosDao] found for dependency
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.abc.www.dao.itf.TeacherDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=hosDao)}
原因: 网上说的注解没生效,或xml没配置该dao是原因之一, 但我遇到的由于图省事复制了其它类来改, 导致继承错误,
如下面, 明明应该继承StudentDao的
@Repository("teacherDao")
public class TeacherDaoImpl implements StudentDao {
}
springMVC中的参数乱码
如下图中的name乱码
@RequestMapping({ "student/insert.do" })
public void nameLike(HttpServletRequest req, String name) throws Exception {
}
此时由于name的获取是自动化的 , 我们可以先用下面的方式判断下倒底传过来的是不是ISO8859-1,
如果name1乱码, 而name2不乱码, 那就请求方提供地址的就是ISO8859-1的,不然请求方给的地址就是UTF-8编码
req.setCharacterEncoding("UTF-8");
String name1 = req.getParameter("name");
String name2= new String(name1.getBytes("ISO8859-1"),"UTF-8");
而如果无论如何都是乱码, 那么很有可能是java原生的URLConnection请求时的地址没有经过java.net.URLEncode("xxx","UTF-8");
试着吧想请求的地址?后的parameter的value值使用java.net.URLEncode("xxx","UTF-8");encode一下,再请求一般就不会乱码了.
String arg = URLEncoder.encode("中国","UTF-8");
url = new URL(urlStr+"?deptname="+arg);
获取所有springmvc中全部接口信息
package com.ngari.www.controller; import java.util.Map; import javax.servlet.http.HttpServletRequest; 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.ResponseBody; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; @Controller @RequestMapping("url/") public class UrlController { @Autowired private RequestMappingHandlerMapping requestMappingHandlerMapping; @Autowired private HttpServletRequest request; /** * 获取当前项目中的全部接口 * */ @RequestMapping(value = "getAllUrl") @ResponseBody public String getAllUrl() { StringBuilder sb = new StringBuilder(); sb.append("URL").append("--").append("Class").append("--").append("Function").append('\n'); Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods(); int i=1; for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) { RequestMappingInfo info = m.getKey(); HandlerMethod method = m.getValue(); sb.append(i+":").append(info.getPatternsCondition()).append("--"); sb.append(method.getMethod().getDeclaringClass()).append("--"); sb.append(method.getMethod().getName()).append('\n'); i++; } System.out.println(sb); return sb.toString(); } /* * 获取当前访问url * */ @RequestMapping(value = "getUrl") @ResponseBody public String getUrl() { String url = ""; String scheme = request.getScheme(); String serverName = request.getServerName(); int serverPort = request.getServerPort(); String servletPath = request.getServletPath(); url = scheme +"://" + serverName +":" +serverPort+servletPath; if (request.getQueryString() != null){ url += "?" + request.getQueryString(); } System.out.println(url); return url; } }
访问 http://localhost:8080/youContextPath/url/getUrl 获取当前访问路径.
访问 http://localhost:8080/youContextPath/url/getAllUrl 之后得到如下接口列表信息:
URL--Class--Function 1:[/bed/update.do]--class com.ngari.www.controller.BedController--update 2:[/bed/insert.do]--class com.ngari.www.controller.BedController--insert
@ControllerAdvice 全局异常捕获配置$$$$$$$$$$
简介
通过@ControllerAdvice注解可以将对于控制器的全局配置放在同一个位置。
注解了@Controller的类的方法可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上。
@ControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上
@ExceptionHandler:用于全局处理控制器里的异常。
用法
import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; @ControllerAdvice public class BusinessExceptionHandler { @ExceptionHandler(value = Exception.class) @ResponseBody public String exceptionHandler(HttpServletRequest request, Exception e) { // e.printStackTrace(); // 把异常信息转成json后返回 JSON.toJsonString(xxx) String ret = String.format("@ControllerAdvice <br/>public String exceptionHandler(HttpServletRequest request, Exception e) <hr/> <br/><br/> Class : [%s] <br/><br/> Message : [%s]<br/><br/>" , e.getClass().toString(), e.getMessage().toString() ); return ret; } }
加了这个全局配置的Bean后,以前代码是这样的,多了很多无关信息。几乎每个类都要try catch一下,代码极度冗余。
@RequestMapping(value = "queryDetail") @ResponseBody public JsonBackData queryDetail(@RequestParam String id) { JsonBackData back = new JsonBackData(); try { OpenSourceThrottleAdjustVO vo = openSourceThrottlePlanQueryService.findById(id); back.setBackData(vo); back.setSuccess(true); back.setBackMsg("查询详细信息成功"); } catch (BusinessException e) { back.setSuccess(false); back.setBackMsg("查询详细信息失败:" + e.getMessage()); } return back; }
但是自从有了@ControllerAdvice 全局处理控制器的异常处理后, 代码就变成了下面的了:
@RequestMapping(value = "queryDetail") @ResponseBody public JsonBackData queryDetail(@RequestParam String id) { JsonBackData back = new JsonBackData(); OpenSourceThrottleAdjustVO vo = openSourceThrottlePlanQueryService.findById(id); back.setBackData(vo); back.setSuccess(true); back.setBackMsg("查询详细信息成功"); return back; }
本小节参考自: https://www.cnblogs.com/donghang/p/9233653.html
a

浙公网安备 33010602011771号