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: 事务不起作用

 

Spring4和Hibernate4整合后事务不起作用--https://blog.csdn.net/qq_23703157/article/details/78681066?locationNum=10&fps=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

posted @ 2015-12-01 11:17  苦涩泪滴  阅读(326)  评论(0)    收藏  举报