Spring配置文件详解:
与
在使用 标签配置时,默认配置了
RequestMappingHandlerAdapter
当两种标签都没有的时候,框架默认注册的有AnnotationMethodHandlerAdapter这个bean,所以能够处理@RequestMapping这个注解,但是只配置了时所注册的三个bean都不能处理@RequestMapping注解,因此无法找到相应的Controller,进而无法进行访问路径的映射,当两种标签都有的时候,会注册一个RequestMappingHandlerAdapter的bean,这个bean能够处理@RequestMapping这个注解。当只配置了
时,
SpringMVC会遇到静态资源无法加载的问题。
问题来源于在web.xml中的对spring的DispatcherServlet采用了如下配置,即url-pattern设置为了“/”,这样便要求SpringMVC处理所有的浏览器请求。
SpringMVC处理客户请求通常是在controller类中使用@RequestMapping注解,显然这个方法无法用于静态资源,所以就会出现静态资源无法获取的404错误。
这种情况下浏览器的jsp请求能够成功是以为Tomcat容器默认配置了jsp Servlet,由于Tomcat的url-pattern是“.jsp”,属于扩展名匹配,优先级高于“/”匹配,所以jsp Servlet会被容器调用,不会出现jsp资源无法获取的问题。
spring 使用说明(转)
———>取代
在xml配置了这个标签后,spring可以自动去扫描base-pack下面或者子包下面的java文件,如果扫描到有@Component @Controller@Service等这些注解的类,则把这些类注册为bean
注意:如果配置了那么标签就可以不用再xml中配置了,因为前者包含了后者。另外
component
-
scan
/>还提供了两个子标签
1.
2.
在说明这两个子标签前,先说一下有一个use-default-filters属性,改属性默认为true,这就意味着会扫描指定包下的全部的标有@Component的类,并注册成bean.也就是@Component的子注解@Service,@Reposity等。所以如果仅仅是在配置文件中这么写
"tv.huan.weisp.web"
/>
Use-default-filter此时为true那么会对base-package包或者子包下的所有的进行java类进行扫描,并把匹配的java类注册成bean。
可以发现这种扫描的粒度有点太大,如果你只想扫描指定包下面的Controller,该怎么办?此时子标签就起到了勇武之地。如下所示
这样就会只扫描base-package指定下的有@Controller下的java类,并注册成bean
但是因为use-dafault-filter在上面并没有指定,默认就为true,所以当把上面的配置改成如下所示的时候,就会产生与你期望相悖的结果(注意base-package包值得变化)
此时,spring不仅扫描了@Controller,还扫描了指定包所在的子包service包下注解@Service的java类
此时指定的include-filter没有起到作用,只要把use-default-filter设置成false就可以了。这样就可以避免在base-packeage配置多个包名这种不是很优雅的方法来解决这个问题了。
另外在我参与的项目中可以发现在base-package指定的包中有的子包是不含有注解了,所以不用扫描,此时可以指定来进行过滤,说明此包不需要被扫描。综合以上说明
Use-dafault-filters=”false”的情况下:指定的不扫描,指定的扫描
注解意义
特别是下面那段英文很重要,我就曾经遇到过加入了jackson的core和mapper包之后竟然不写配置文件也能自动转换成json,我当时很费解。原来是
这个东西在起作用。
是一种简写形式,完全可以手动配置替代这种简写形式,简写形式可以让初学都快速应用默认配置方案。 会自动注册DefaultAnnotationHandlerMapping与AnnotationMethodHandlerAdapter 两个bean,是spring MVC为@Controllers分发请求所必须的。
并提供了:数据绑定支持,@NumberFormatannotation支持,@DateTimeFormat支持,@Valid支持,读写XML的支持(JAXB),读写JSON的支持(Jackson)。
在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model 返回给对应的View 进行展示
Spring的注解详解:
-——>@RequestMapping :
1.@RequestMapping注解是
用来处理前端请求地址映射的,注解
用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
2.
@RequestMapping
属性
value: 指定请求的实际地址,指定的地址可以是URI Template 模式
method: 指定请求的method类型, GET、POST、PUT、DELETE等;
GET一般用于
获取/查询
资源信息,而POST一般用于
更新
资源信息。
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html;
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
params: 指定request中必须包含某些参数值是,才让该方法处理。
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求。
详细解说:
------->
使用 @RequestMapping 来映射 Request 请求与处理器
如:
@Controller
@RequestMapping (
"/test/{variable1}"
)
public
class
MyController {
@RequestMapping (
"/showView/{variable2}"
)
public
ModelAndView showView( @PathVariable String variable1, @PathVariable ( "variable2" )
int
variable2) {
ModelAndView modelAndView
=
new
ModelAndView();
modelAndView.setViewName(
"viewName"
);
modelAndView.addObject(
" 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 "
);
return
modelAndView;
}
}
代码中我们定义了两个URI 变量,一个是控制器类上的variable1 ,一个是showView 方法上的variable2 ,然后在showView 方法的参数里面使用
@PathVariable
标记使用了这两个变量。所以当我们使用/test/hello/showView/2.do 来请求的时候就可以访问到MyController 的showView 方法,这个时候variable1 就被赋予值hello ,variable2 就被赋予值2 ,然后我们在showView 方法参数里面标注了参数variable1 和variable2 是来自访问路径的path 变量,这样方法参数variable1 和variable2 就被分别赋予hello 和2 。方法参数variable1 是定义为String 类型,variable2 是定义为int 类型,像这种简单类型在进行赋值的时候Spring 是会帮我们自动转换的
注:
在上面的代码中我们可以看到在标记variable1 为path 变量的时候我们使用的是@PathVariable ,而在标记variable2 的时候使用的是@PathVariable(“variable2”) 。这两者有什么区别呢?
第一种情况就默认去URI 模板中找跟参数名相同的变量,但是这种情况只有在使用debug 模式进行编译的时候才可以,而第二种情况是明确规定使用的就是URI 模板中的variable2 变量。当不是使用debug 模式进行编译,或者是所需要使用的变量名跟参数名不相同的时候,就要使用第二种方式明确指出使用的是URI 模板中的哪个变量。
----------->使用 @RequestMapping 的一些高级用法
(1)
params属性
@RequestMapping (value= "testParams" , params={ "param1=value1" , "param2" , "!param3"
})
public
String testParams() {
System. out .println(
"test Params..........."
);
return
"testParams"
;
}
用@RequestMapping 的params 属性指定了三个参数,这些参数都是针对请求参数而言的,它们分别表示参数param1 的值必须等于value1 ,参数param2 必须存在,值无所谓,参数param3 必须不存在,只有当请求/testParams.do 并且满足指定的三个参数条件的时候才能访问到该方法。所以当请求/testParams.do?param1=value1¶m2=value2 的时候能够正确访问到该testParams 方法,当请求/testParams.do?param1=value1¶m2=value2¶m3=value3 的时候就不能够正常的访问到该方法,因为在@RequestMapping 的params 参数里面指定了参数param3 是不能存在的。
(2)method属性
@RequestMapping (value= "testMethod" , method=
{RequestMethod. GET , RequestMethod. DELETE })
public
String testMethod() {
return
"method"
;
}
在上面的代码中就使用method 参数限制了以GET 或DELETE 方法请求/testMethod 的时候才能访问到该Controller 的testMethod 方法。
(3)headers属性
@RequestMapping (value= "testHeaders" , headers={ "host=localhost" , "Accept"
})
public
String testHeaders() {
return
"headers"
;
}
headers 属性的用法和功能与params 属性相似。在上面的代码中当请求/testHeaders.do 的时候只有当请求头包含Accept 信息,且请求的host 为localhost 的时候才能正确的访问到testHeaders 方法。
————>@Resource和@Autowired
@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
@Autowired为Spring提供的注解
经常使用的是:@Resource,它有两个重要的属性:name和type,name属性解析为bean的名字,而type属性则解析为bean的类型。
———>
@ModelAttribute和 @SessionAttributes
@ModelAttribute
代表的是:该Controller的所有方法在调用前,先执行此@ModelAttribute方法,可用于注解和方法参数中,可以把这个@ModelAttribute特性,应用在BaseController当中,所有的Controller继承BaseController,即可实现在调用Controller时,先执行@ModelAttribute方法。
@SessionAttributes即将值放到session作用域中,写在class上面。
如:
———————>使用 @ModelAttribute 和 @SessionAttributes 传递和保存数据
SpringMVC 支持使用 @
ModelAttribute
和 @
SessionAttributes
在不同的模型(model)和控制器(Controller)之间共享数据。
@ModelAttribute
主要有两种使用方式,一种是标注在方法上,一种是标注在 Controller 方法参数上。
当 @
ModelAttribute
标记在方法上的时候,该方法将在处理器方法执行之前执行,然后把返回的对象存放在 session 或模型属性中,属性名称可以使用 @
ModelAttribute
(“attributeName”) 在标记方法的时候指定,若未指定,则使用返回类型的类名称(首字母小写)作为属性名称。关于 @ModelAttribute 标记在方法上时对应的属性是存放在 session 中还是存放在模型中,我们来做一个实验,看下面一段代码。
@Controller
@RequestMapping (
"/myTest"
)
public
class
MyController {
@ModelAttribute (
"hello"
)
public
String getModel() {
System. out .println(
"-------------Hello---------"
);
return
"world"
;
}
@ModelAttribute (
"intValue"
)
public
int
getInteger() {
System. out .println(
"-------------intValue---------------"
);
return
10
;
}
@RequestMapping (
"sayHello"
)
public
void
sayHello( @ModelAttribute ( "hello" ) String hello, @ModelAttribute ( "intValue" )
int
num, @ModelAttribute ( "user2" ) User user, Writer writer, HttpSession session)
throws
IOException {
writer.write(
"Hello " + hello + " , Hello " + user.getUsername() +
num);
writer.write(
"\r"
);
Enumeration enume
=
session.getAttributeNames();
while
(enume.hasMoreElements())
writer.write(enume.nextElement()
+ "\r"
);
}
@ModelAttribute (
"user2"
)
public
User getUser(){
System. out .println(
"---------getUser-------------"
);
return
new
User(3, "user2"
);
}
}
当我们请求 /myTest/sayHello.do 的时候使用 @ModelAttribute 标记的方法会先执行,然后把它们返回的对象存放到模型中。最终访问到 sayHello 方法的时候,使用 @ModelAttribute 标记的方法参数都能被正确的注入值。执行结果如下所示:
Hello world,Hello user210
由执行结果我们可以看出来,此时 session 中没有包含任何属性,也就是说上面的那些对象都是存放在模型属性中,而不是存放在 session 属性中。那要如何才能存放在 session 属性中呢?这个时候我们先引入一个新的概念 @SessionAttributes ,它的用法会在讲完 @ModelAttribute 之后介绍,这里我们就先拿来用一下。我们在 MyController 类上加上 @SessionAttributes 属性标记哪些是需要存放到 session 中的。看下面的代码:
@Controller
@RequestMapping (
"/myTest"
)
@SessionAttributes (value
={ "intValue" , "stringValue" }, types={User.
class
})
public
class
MyController {
@ModelAttribute (
"hello"
)
public
String getModel() {
System. out .println(
"-------------Hello---------"
);
return
"world"
;
}
@ModelAttribute (
"intValue"
)
public
int
getInteger() {
System. out .println(
"-------------intValue---------------"
);
return
10
;
}
@RequestMapping (
"sayHello"
)
public
void
sayHello(Map map, @ModelAttribute ( "hello" ) String hello, @ModelAttribute ( "intValue" )
int
num, @ModelAttribute ( "user2" ) User user, Writer writer, HttpServletRequest request)
throws
IOException {
map.put(
"stringValue" , "String"
);
writer.write(
"Hello " + hello + " , Hello " + user.getUsername() +
num);
writer.write(
"\r"
);
HttpSession session
=
request.getSession();
Enumeration enume
=
session.getAttributeNames();
while
(enume.hasMoreElements())
writer.write(enume.nextElement()
+ "\r"
);
System. out .println(session);
}
@ModelAttribute (
"user2"
)
public
User getUser() {
System. out .println(
"---------getUser-------------"
);
return
new
User(3, "user2"
);
}
}
在上面代码中我们指定了属性为 intValue 或 stringValue 或者类型为 User 的都会放到 Session中,利用上面的代码当我们访问 /myTest/sayHello.do 的时候,结果如下:
Hello world,Hello user210
仍然没有打印出任何 session 属性,这是怎么回事呢?怎么定义了把模型中属性名为 intValue 的对象和类型为 User 的对象存到 session 中,而实际上没有加进去呢?难道我们错啦?我们当然没有错,只是在第一次访问 /myTest/sayHello.do 的时候 @SessionAttributes 定义了需要存放到 session 中的属性,而且这个模型中也有对应的属性,但是这个时候还没有加到 session 中,所以 session 中不会有任何属性,等处理器方法执行完成后 Spring 才会把模型中对应的属性添加到 session 中。所以当请求第二次的时候就会出现如下结果:
Hello world,Hello user210
user2
intValue
stringValue
当 @ModelAttribute 标记在处理器方法参数上的时候,表示该参数的值将从模型或者 Session 中取对应名称的属性值,该名称可以通过 @ModelAttribute(“attributeName”) 来指定,若未指定,则使用参数类型的类名称(首字母小写)作为属性名称。
————>
@PathVariable
用于将请求URL中的模板变量映射到功能处理方法的参数上,即取出uri模板中的变量作为参数。如:
@Controller
public
class
TestController {
@RequestMapping(value
="/user/{userId}/roles/{roleId}",method =
RequestMethod.GET)
public
String getLogin(@PathVariable("userId"
) String userId,
@PathVariable(
"roleId"
) String roleId){
System.out.println(
"User Id : " +
userId);
System.out.println(
"Role Id : " +
roleId);
return
"hello"
;
}
}
-------->
@requestParam
@requestParam主要用于在SpringMVC后台控制层获取参数,类似一种是request.getParameter("name"),它有三个常用参数:defaultValue = "0", required = false, value = "isApp";defaultValue 表示设置默认值,required 铜过boolean设置是否是必须要传入的参数,value 值表示接受的传入的参数类型。
@RequestBody
作用:
i) 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
ii) 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
使用时机:
A) GET、POST方式提时, 根据request header Content-Type的值来判断:
- application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据@RequestParam, @ModelAttribute也可以处理,当然@RequestBody也能处理);
- multipart/form-data, 不能处理(即使用@RequestBody不能处理这种格式的数据);
- 其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用@RequestBody来处理);
---------->
@ResponseBody
作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。
使用时机:返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
------>
@Component
相当于通用的注解,当不知道一些类归到哪个层时才使用,一般不建议使用。
--------->
@Repository
用于注解dao层,在daoImpl类上面注解。