Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service 和 @Controller。
在目前的 Spring 版本中,这 3 个注释和 @Component 是等效的,如果 Web 应用程序采用了经典的三层分层结构的话,最好在持久层、业务层和控制层分别采用上述注解对分层中的类进行注释。
@Service用于标注业务层组件
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Service
public class VentorServiceImpl implements iVentorService {
}
@Repository
public class VentorDaoImpl implements iVentorDao {
}
在一个稍大的项目中,如果组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找以及维护起来也不太方便。
Spring2.5为我们引入了组件自动扫描机制,他在类路径下寻找标注了上述注解的类,并把这些类纳入进spring容器中管理。
它的作用和在xml文件中使用bean节点配置组件时一样的。要使用自动扫描机制,我们需要打开以下配置信息:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package=”com.eric.spring”>
</beans>
1.annotation-config是对标记了 Spring's @Required、@Autowired、JSR250's @PostConstruct、@PreDestroy、@Resource、JAX-WS's @WebServiceRef、EJB3's @EJB、JPA's @PersistenceContext、@PersistenceUnit等注解的类进行对应的操作使注解生效。
2.base-package为需要扫描的包(含所有子包),负责扫描那些类有注解。
getBean的默认名称是类名(头字母小写),如果想自定义,可以@Service(“aaaaa”)这样来指定。
这种bean默认是“singleton”的,如果想改变,可以使用@Scope(“prototype”)来改变。
可以使用以下方式指定初始化方法和销毁方法:
@PostConstruct
public void init() {
}
@PreDestroy
public void destory() {
}
注入方式:
@Autowired
@Autowired顾名思义,就是自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。
注入时不要new 这个注入的类,因为spring会自动注入,如果手动再new的话会出现错误,然后属性加上@Autowired后不需要getter()和setter()方法
当然,getter看个人需求,如果私有属性需要对外提供的话,应当予以保留。
@Autowired接口注入
上面的比较简单,我们只是简单注入一个Java类,那么如果有一个接口,有多个实现,Bean里引用的是接口名,又该怎么做呢?比如有一个Car接口:
public interface Car
{
public String carName();
}
两个实现类BMW和Benz:
@Service
public class BMW implements Car
{
public String carName()
{
return "BMW car";
}
}
@Service
public class Benz implements Car
{
public String carName()
{
return "Benz car";
}
}
写一个CarFactory,引用Car:
@Service
public class CarFactory
{
@Autowired
private Car car;
public String toString()
{
return car.carName();
}
}
不用说,一定是报错的,Car接口有两个实现类,Spring并不知道应当引用哪个实现类。这种情况通常有两个解决办法:
1、删除其中一个实现类,Spring会自动去base-package下寻找Car接口的实现类,发现Car接口只有一个实现类,便会直接引用这个实现类
2、实现类就是有多个该怎么办?此时可以使用@Qualifier注解:当接口存在两个实现类的时候必须使用@Qualifier指定注入哪个实现类
@Service
public class CarFactory
{
@Autowired
@Qualifier("BMW")
private Car car;
public String toString()
{
return car.carName();
}
}
注意@Qualifier注解括号里面的应当是Car接口实现类的类名,我之前试的时候一直以为是bean的名字,所以写了"bMW",结果一直报错。
@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解
1、共同点
两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。
@Resource
@Service
public class Zoo
{
@Resource(name = "tiger")
private Tiger tiger;
@Resource(type = Monkey.class)
private Monkey monkey;
public String toString()
{
return tiger + "\n" + monkey;
}
}
这是详细一些的用法,说一下@Resource的装配顺序:
1、@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
2、指定了name或者type则根据指定的类型去匹配bean
3、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错
然后,区分一下@Autowired和@Resource两个注解的区别:
1、@Autowired默认按照byType方式进行bean匹配,
@Resource默认按照byName方式进行bean匹配
2、@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了
Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。
<!-- 定义跳转的文件的前后缀 ,视图模式配置-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
@Controller
@RequestMapping ( "/test" )
public class MyController {
1. 返回ModelAndView
//@RequestMapping ( "/showView" )
@RequestMapping(value = "/showView", method = RequestMethod.GET)
public ModelAndView showView() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("viewName"); // 跳转的页面
modelAndView.addObject( " 需要放到 model 中的属性名称 " , " 对应的属性值,它是一个对象 " );
// modelAndView.addObject("users", users);
return modelAndView;
}
//当访问localhost:8080/hello?username=ted时,值ted会绑定到参数username上,结果是 Hello ted
@RequestMapping(value=/hello)
String sayHelloToUser(@RequestParam("username") String username){
return "Hello " + username;
// return "items/edititems";
}
3. 返回字符串
// @RequestMapping 来处理多个 URI
@RequestMapping(value={"", "/page", "page*","view/*"})
String multipleMapping(){
return "Hello";
}
- localhost:8080/home
- localhost:8080/home/
- localhost:8080/home/page
- localhost:8080/home/pageabc
- localhost:8080/home/view/
- localhost:8080/home/view/vi
@RequestMapping("/list")
public String userList(Model model){
User user = new User();
model.addAttribute("user", User);
return "operator/list";
}
页面上${user}获得对象,${user.userName}获得用户名(对象点属性)
也可以返回Model,方式多种多样,这样子写你可能更容易理解一些。
如果是ajax异步调用的话,需要加上@ResponseBody标签,在返回的时候随便返回对象,集合,字符串等的都可以的。
只想返回数据而不返回页面时
//@RequestMapping("c")
@RequestMapping(value=/c)
@ResponseBody
public String d()
{
HashMap s = new HashMap();
s.put("aaa", "你好啊");
return s;
}
@RestController的意思就是controller里面的方法都以json格式输出,
@RestController
public class HelloWorldController {
@RequestMapping("/hello")
public String index() {
return "Hello World";
}
}
在方法上添加
使用@RestController注解等于使用@Controller和@ResponseBody两个注解。返回对象
标注@ResponseBody就是输出json
@RestController
public class LoginController {
......
@RequestMapping("/login")
public User login(User user){
......
return user; }
@Controller
@ResponseBody
public class LoginController {
......
@RequestMapping("/login")
public User login(User user){
......
return user; }
那么在前台接收到的数据为:'{"userName":"xxx","pwd":"xxx"}'
或者在方法上
@RequestMapping("/login")
@ResponseBody
public User login(User user){
......
return user;
}
效果等同于如下代码:
@RequestMapping("/login")
public void login(User user, HttpServletResponse response){
......
response.getWriter.write(JSONObject.fromObject(user).toString());
}