1、@Controller (注入服务)
@Component扩展,被@Controller注解的类表示Web层实现,从而见到该注解就想到Web层实现,使用方式和@Component相同;
在SpringMVC中只需要使用这个标记一个类是Controller,然后使用@RequestMapping和@RequestParam等一些注解用以定义URL请求和Controller方法之间的映射,这样的Controller就能被外界访问到。此外,Controller不会直接依赖于HttpServletRequest 和HttpServletResponse 等HttpServlet 对象,他们可以通过Controller的方法参数灵活的获取到。
举个例子:
@Controller
public class TestController {
@RequestMapping ( "/showView" )
public ModelAndView showView() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName( "viewName" );
modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " );
return modelAndView;
}
}
在上面的例子中,@Controller是标记在类TestController上面的, 所以类TestController就是一个SpringMVC Controller对象。分发处理器会扫描使用了该注解的类的方法,并检测该方法是否调用了@RequestMapping注解。@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是真正处理请求的处理器。然后使用@RequestMapping ( “/showView” )标记在Controller方法上,表示当请求/showView.do 的时候访问的是TestController 的showView 方法,该方法返回了一个包括Model 和View 的ModelAndView 对象。
单单使用@Controller 标记在一个类上还不能真正意义上的说它就是SpringMVC 的一个控制器类,因为这个时候Spring 还不认识它。那么要如何做Spring 才能认识它呢?这个时候就需要把这个控制器类交给Spring 来管理。
第一种方式是在SpringMVC 的配置文件中定义MyController 的bean 对象。
第二种方式是在SpringMVC 的配置文件中告诉Spring 该到哪里去找标记为@Controller 的Controller 控制器。 < context:component-scan base-package = "com.host.app.web.controller" >
< context:exclude-filter type = "annotation"
expression = "org.springframework.stereotype.Service" />
</ context:component-scan >
**注:**上面 context:exclude-filter 标注的是不扫描 @Service 标注的类
2、@RequestMapping
使用 @RequestMapping 来映射 Request 请求与处理器,通过这个注解可以定义不同的处理器映射规则,即为控制器指定可以处理哪些URL请求。
用@RequestMapping 来映射URL 到控制器类,或者是到Controller 控制器的处理方法上。当@RequestMapping 标记在Controller 类上的时候,里面使用@RequestMapping 标记的方法的请求地址都是相对于类上的@RequestMapping 而言的;当Controller 类上没有标记@RequestMapping 注解时,方法上的@RequestMapping 都是绝对路径。这种绝对路径和相对路径所组合成的最终路径都是相对于根路径“/ ”而言的。
在上面那个例子中:
这个控制器里因为TestController 没有被@RequestMapping 标记,所以当需要访问到里面使用了@RequestMapping 标记的showView 方法时,就是使用的绝对路径/showView.do 请求就可以了。
如果改成这样:
@Controller
@RequestMapping ( "/test" )
public class TestController {
@RequestMapping ( "/showView" )
public ModelAndView showView() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName( "viewName" );
modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " );
return modelAndView;
}
}
这种情况下是在控制器上加了@RequestMapping 注解,所以当需要访问到里面使用了@RequestMapping 标记的方法showView() 的时候就需要使用showView 方法上@RequestMapping 相对于控制器TestController上@RequestMapping 的地址,即/test/showView.do 。
URL路径映射:@RequestMapping("/hello"),可以将多个url映射到同一个方法上。
窄化请求映射:
(1)在class上面添加@RequestMapping(url)指定通用请求前缀,限制此类下的所有方法请求url必须以请求前缀开头,通过此方法来分类管理url;
(2)在方法名上面再设置请求映射url,即添加@RequestMapping注解在方法名上。return “/WEB-INF/jsp/login.jsp” 调用这个方法,重定向的到指定的jsp页面或制定的@RequestMapping的请求路径;
(3)在浏览器上输入相应地址,完成访问。
3、@RequestBody
用于读取http请求的内容(字符串),通过springMVC提供的HttpMessageConverter接口将读取到的内容转换为json、xml等格式的数据,再转换为java对象绑定到Controller类方法的参数上。
简单点来说,就是把json格式的数据转换为java对象,就举个例子来说明:
编写一个jsp页面来向后台传递json格式的数据(切记是json格式的):
<script>
jsonData();
function jsonData()
{
$.ajax({
url:"<%=path%>/user/jsonTest.do",
contentType:'application/json;charset=utf-8',//设置json格式
data:'{"username":"张三":"address":"福州"}',
type:'post',
success:function(data){
alert(data);
},error:function(error){
alert(error);
}
})
}
</script>
然后在后台接收一下:
@RequestMapping("/jsonTest.do")
public void jsonTest(@RequestBody User user) throws Exception
{
System.out.println(user.toString());
}
这样的话,前台的两个json数据就会自动匹配到User这个对象的属性中了,当然属性名称要一样的。
查看一下结果:
可以看到User这个对象中的username和address都已经自动赋值好了,这个就是json格式的数据转java对象了,可以省去我们在后台将json转成java对象。不过在使用的时候,要注意两边的名称要相同,前台的username要对应java对象中的username这样才能成功。否则得到如下:
4、@ResponseBody
含义:
@Responsebody 注解表示该方法的返回的结果直接写入 HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @Responsebody 后返回结果不会被解析为跳转路径,而是直接写入HTTP 响应正文中。
作用:
用于将Controller中方法返回的对象通过适当的HttpMessageConverter转换为指定格式的数据,如:json、xml等,然后写入到response对象的body区,通过Response响应给客户端。需要注意的是,在使用此注解之后不会再走试图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。
使用时机:
返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;
举个例子:
@RequestMapping("/login")
@ResponseBody
public User login(User user){
return user;
}
User字段是:userName pwd
那么在前台接收到的数据为:’{“userName”:“xxx”,“pwd”:“xxx”}’
效果等同于如下代码:
@RequestMapping("/login")
public void login(User user, HttpServletResponse response){
response.getWriter.write(JSONObject.fromObject(user).toString());
}
5、@ModelAttribute
在方法定义上使用该注解: SpringMVC在调用目标处理方法前, 会先逐个调用在方法级上标注了@ModelAttribute的方法;
在方法的入参前使用该注解:可以从隐含对象中获取隐含的模型数据中获取对象,再将请求参数 –绑定到对象中,再传入入参将方法入参对象添加到模型中。
6、@RequestParam
处理简单类型的绑定,用 @RequestParam 绑定 HttpServletRequest 请求参数到控制器方法参数,即在处理方法入参处使用该注解,可以把请求参数传递给请求方法。
@RequestMapping ( "requestParam" )
public String testRequestParam( @RequestParam(required=false) String name, @RequestParam ( "age" ) int age) {
return "requestParam" ;
}
在上面代码中利用@RequestParam 从HttpServletRequest 中绑定了参数name 到控制器方法参数name ,绑定了参数age 到控制器方法参数age 。当没有明确指定从request 中取哪个参数时,Spring 在代码是debug 编译的情况下会默认取跟方法参数同名的参数,如果不是debug 编译的就会报错。此外,当需要从request 中绑定的参数和方法的参数名不相同的时候,也需要在@RequestParam 中明确指出是要绑定哪个参数。在上面的代码中如果访问 /requestParam.do?name=hello&age=1 则Spring 将会把request请求参数name的值hello赋给对应的处理方法参数name ,把参数age 的值1 赋给对应的处理方法参数age 。
在@RequestParam 中除了指定绑定哪个参数的属性value之外,还有一个属性required,它表示所指定的参数是否必须在request 属性中存在,默认是true,表示必须存在,当不存在时就会报错。在上面代码中我们指定了参数name的required的属性为false ,而没有指定age 的required 属性,这时候如果我们访问/requestParam.do而没有传递参数的时候,系统就会抛出异常,因为age 参数是必须存在的,而我们没有指定。而如果我们访问 /requestParam.do?age=1 的时候就可以正常访问,因为我们传递了必须的参数age ,而参数name是非必须的,不传递也可以。
『
value:参数名,即入参的请求参数名字
如:value=“id”,表示将请求的参数区的名字为id的参数的值等待传入;
require:是否必需,默认是true,表示请求中一定要有相应的参数,否则会报400错误。且在每个参数定义前设置。
defaultValue:默认值,表示如果请求中没有同名参数时的默认值。
通过 require=true 限定参数id必须传递,如果不传递会报400错误;
可以使用defaultValue设置默认值,即使 require=true 也可以不传递id参数。
』
7、@PathVariable 绑定URL占位符到入参。
8、@ExceptionHandler 注解到方法上, 出现异常时会执行该方法。
9、@ControllerAdvice 使一个Controller成为全局的异常处理类, 类中用ExceptinHandler方法注解的方法可以处理所有Controller发生的异常。
10、@Autowired
它可以对类成员变量、方法以及构造函数进行标注,完成自动装配的工作。自动装配的意思就是让Spring从应用上下文中找到对应的bean的引用,并将它们注入到指定的bean。通过@Autowired注解可以完成自动装配。使用@Autowired 来消除代码Java代码里面的getter/setter与bean属性中的property。当然,getter看个人需求,如果私有属性需要对外提供的话,应当予以保留。
只要对应类型的bean有且只有一个,则会自动装配到该属性上。如果没有找到对应的bean,应用会抛出对应的异常,如果想避免抛出这个异常,则需要设置@Autowired(required=false)。不过,在应用程序设计中,应该谨慎设置这个属性,因为这会使得你必须面对NullPointerException的问题。
如果存在多个同一类型的bean,则Spring会抛出异常,表示装配有歧义,解决办法有两个:
(1)通过@Qualifier注解指定需要的bean的ID;
(2)通过@Resource注解指定注入特定ID的bean;
@Autowired 和 @Service("")的配合使用:
实例:
@Controller
@RequestMapping("/test")
public class StudentController {
@Autowired
private StudentService studentService;
@RequestMapping("getInfo")
@ResponseBody
public int getInfo(Student student){
return studentService.insertStu(student);
}
}
在Controller中对私有变量用@Autowired标注,因为studentService这个变量是service层接口,所以要找到他的实现类StudentServiceImpl,并在实现类上添加@Service("")的注释。
@Service("StudentService")
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao studentDao;
public int insertStu(Student student){
return studentDao.insertInfo(student);
}
}
如果不添加@Service("")注释,会报如下错误。因为@Autowired 将寻找与之匹配的bean来创建(类名)bena,但因为删除接口实现类上@Service("")注解,找不到服务对象,@Autowired自然也就找不到实例bean了。
11、@Override
@Override是伪代码,表示重写(当然不写也可以),不过也有好处:
(1)可以当注释用,方便阅读;
(2)编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错。
例如,你如果没写@Override,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法。
举例:在重写父类的onCreate时,在方法前面加上@Override 系统可以帮你检查方法的正确性。
@Override
public void onCreate(Bundle savedInstanceState)
{…….}
这种写法是正确的,如果你写成:
@Override
public void oncreate(Bundle savedInstanceState)
{…….}
编译器会报如下错误:
The method oncreate(Bundle) of type HelloWorld must override or implement a supertype method,以确保你正确重写onCreate方法(因为oncreate应该为onCreate)。
而如果你不加@Override,则编译器将不会检测出错误,而是会认为你为子类定义了一个新方法:oncreate
12、@Transactional
使用时机:
对数据库的数据进行批量或连表操作时,为了保证数据的一致性和正确性,则需要添加事务管理机制进行管理;
当对数据库的数据操作失败时,事务管理可以很好保证所有的数据 回滚 到原来的数据,如果操作成功,则保证所有的需要更新的数据持久化。
『
回滚(Rollback)指的是程序或数据处理错误,将程序或数据恢复到上一次正确状态的行为。
回滚包括程序回滚和数据回滚等类型。
删除由一个或多个部分完成的事务执行的更新。为保证应用程序、数据库或系统错误后还原数据库的完整性,需要使用回滚。
回滚泛指程序更新失败, 返回上一次正确状态的行为。
回滚与恢复有本质的区别。
升级回滚:是指因升级中所发生的意外而自动回滚。
』
使用优点:
(1)开发团队达成一致约定,明确标注事务方法的编程风格;
(2)保证事务方法的执行时间尽可能短,不要穿插其他网络操作,RPC/HTTP请求或者剥离到事务方法外部;
(3)不是所有的方法都需要事务,如果只有一条修改操作、只读操作不需要事务控制。
13、@Param
mybatis提供了一个使用注解来参入多个参数的方法,这种方法需要在接口的参数上添加@Param注解。
举个例子:
/**
* 更新学生信息
* @param student
* @return
*/
int updateInfo(@Param("student") Student student);
在这个updateInfo的方法中需要传入多个参数,那么在进行mybatis配置的时候,没有办法同事配置多个参数,所以需要@Param这个注解来绑定参数对象。student这个参数中包含了三个对象,用@Param来绑定参数并命名为"student"。并且在mapper.xml文件中调用时,对逐个参数在调用时,要加上 student. 的前缀。如下所示:
<update id="updateInfo">
UPDATE test_student SET name=#{student.name},age=#{student.age} WHERE id=#{student.id}
</update>
注意事项:在使用@Param来注解时,如果使用#{ } 或者 ${ } 的方式都可以,但如果不是用@Param注解时,则必须使用#{ }方式。
14、@Component (把普通pojo实例化到spring容器中,相当于配置文件中的 )
定义Spring管理Bean
在Java配置文件中有两个注解值得注意:
@Configuration 表示这个.java文件是一个配置文件;
@ComponentScan 表示开启Component扫描,Spring将会设置该目录以及子目录下所有被@Component注解修饰的类。
15、@Configuration
表示这个类是一个spring 配置类,一般这里面会定义Bean,会把这个类中bean加载到spring容器中。
@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class})
public class SoundSystemConfig {
}
16、@Bean
在JavaConfig中的属性注入:
@Bean
public CDPlayer cdPlayer() {
return new CDPlayer(sgtPeppers());
}
看起来是函数调用,实际上不是:由于sgtPeppers()方法被@Bean注解修饰,所以Spring会拦截这个函数调用,并返回之前已经创建好的bean——确保该SgtPeppers bean为单例。
17、@ComponentScan
@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中。且这个注解默认会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中。
如果不设置basePackage的话,默认会扫描包的所有类,所以最好还是写上basePackage,减少加载时间。默认扫描**/*.class路径,比如这个注解在com.wuhulala下面,那么会扫描这个包下的所有类还有子包的所有类。比如com.wuhulala.service包的应用。
总结@ComponentScan的常用方式:
自定扫描路径下边带有@Controller,@Service,@Repository,@Component注解加入spring容器
通过includeFilters加入扫描路径下没有以上注解的类加入spring容器
通过excludeFilters过滤出不用加入spring容器的类
自定义增加了@Component注解的注解方式
18、@Service (注入dao)
用于标注服务层,主要用来进行业务的逻辑处理。@Component扩展,被@Service注解的POJO类表示Service层实现,从而见到该注解就想到Service层实现,使用方式和@Component相同;
19、@Repository (实现dao访问)
用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件。@Component扩展,被@Repository注解的POJO类表示DAO层实现,从而见到该注解就想到DAO层实现,使用方式和@Component相同;
@RequestParam和@RequestBody的区别
@RequestParam
A) 常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( 由String到 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值。
B)用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST。(不设置这个属性,好像这就是默认值)
C) 该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定。
在方法参数里面如是:
public WebResponse findReleventPolicyPage(@RequestParam("pageSize") Integer pageSize,
@RequestParam("pageNum") Integer pageNum,
@RequestParam("type") Integer type){}
@RequestBody
处理HttpEntity传递过来的数据,一般用来处理非Content-Type: application/x-www-form-urlencoded编码格式的数据。
GET请求中,因为没有HttpEntity,所以@RequestBody并不适用。
POST请求中,通过HttpEntity传递的参数,必须要在请求头中声明数据的类型Content-Type,SpringMVC通过使用HandlerAdapter 配置的HttpMessageConverters来解析HttpEntity中的数据,然后绑定到相应的bean上。
用于将Controller中方法返回的对象,通过适当的HttpMessageConverter转换为指定格式的数据,如:json、xml等,然后通过Response响应给客户端。
在方法参数里面如是:
@RequestMapping("/json_test")
// 响应json数据,把pojo对象转换成json数据并响应
@ResponseBody
public Items jsonTest (@RequestBody Items items){ // 接受json数据并转换成pojo对象
return items;
}
总结
在GET请求中,不能使用@RequestBody。
在POST请求,可以使用@RequestBody和@RequestParam,但是如果使用@RequestBody,对于参数转化的配置必须统一。
举个例子,在SpringMVC配置了HttpMessageConverters处理栈中,指定json转化的格式,如Date转成‘yyyy-MM-dd’,则参数接收对象包含的字段如果是Date类型,就只能让客户端传递年月日的格式,不能传时分秒。因为不同的接口,它的参数可能对时间参数有不同的格式要求,所以这样做会让客户端调用同事对参数的格式有点困惑,所以说扩展性不高。
如果使用@RequestParam来接受参数,可以在接受参数的model中设置@DateFormat指定所需要接受时间参数的格式。
另外,使用@RequestBody接受的参数是不会被Servlet转化统一放在request对象的Param参数集中,@RequestParam是可以的。
综上所述,一般情况下,推荐使用@RequestParam注解来接受Http请求参数。