相关java代码
这是一个简单显示欢迎词的例子,如果无用户名,欢迎词为Hello,World;如果有用户名,则为Hello,<用户名>。
Service
Service是对业务逻辑的封装,分为接口和具体的实现。一个接口可以有多个实现。
Service接口
/** GreetingService:给出欢迎词接口。*/
public interface GreetingService {
public String getGreeting(String name);
}
Service接口的某个具体的实现
接口可以有多个实现。/** 根据名字给出欢迎词的具体实现*/
@Service
public class GreetingServiceImpl implements GreetingService{
@Override
public String getGreeting(String name) {
return "Hello," + name + "!";
}
}
Controller
Controller将service处理的接口返回给输出的UI界面,或者作为web api的结果进行封装并返回。通过Controller和Service的分离,实现UI和业务逻辑处理的分离。@Controller
public class HelloController {
//【1】实例具体采用那个实现,是在runtime时注入(Dependency Injection)。可以在web.xml及其相关xml中定义,也可以在代码中定义。
// - 在Controller的编写中,我们并不需要考虑具体那个实现。这是spring模块化编程的一大特点。
// - 需提供setter注入bean。
private GreetingService greetingService;
public void setGreetingService(GreetingService greetingService) {
this.greetingService = greetingService;
}
//【2】原始的servlet的通过doGet,doPost来对匹配的url进行处理,在方法中,我们需要根据不同的parameters分别进行处理,包括parameter是否存在,值是什么,这让代码会比较冗长,没有那么清晰。而在spring中:
// @RequestMapping:匹配特定的URL,请求方法,paramter是否存在,header的值,content type,期待的响应类型。
// - url: @RequestMapping("/")
// - url和参数:@RequestMapping(value = "/", params = {"name"})
// - url、参数和方法@RequestMapping(value = "/test", params = {"name"},method = RequestMethod.GET)
// - 本例中,helloWorld的url匹配为/,helloName的url匹配为/且带有name的参数,采用最佳匹配方式。如http://localhost:8080/chapter12/映射到helloWorld来处理,而http://localhost:8080/chapter12/?name=wei映射到helloName()来处理
// @ResponseBody:返回非view(非页面方式),本例直接返回的HTTP body的内容为文本的Hello, World。
@ResponseBody
@RequestMapping("/")
public String helloWorld(){
return "Hello, World!";
}
@ResponseBody
@RequestMapping(value = {"/","/custom"}, params = {"name"})
public String helloName(@RequestParam("name")String name){
return this.greetingService.getGreeting(name);
}
}
设置
应用上下文和bean
Spring Framework容器有一个或者多个Context(org.springframework.context.ApplicationContext),这些Context管理各种各样的bean,即业务逻辑实现、执行任务,存储和获取数据,HTTP请求的响应等java实例。这些bean可用于依赖注入,消息通知,计划方法执行,bean校验等等。本例,我们要将欢迎词的具体实例注入到Controller中。
ApplicationContext有扩展和实现,我们需要根据需求进行配置:
- ConfigurableApplicationContext,用于配置,暂时我们只需关心它
- org.springframework.web.context.WebApplicationContext和org.springframework.web.context.ConfigurableWebApplicationContext用于获取底层的ServletContext以及ServletConfig。
- ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext 用于在独立应用(可运行的jar)从xml中入Spring配置。如同XmlWebApplicationContext 之于J2EE应用。
- 使用java代码进行设置,而非xml,独立应用使用AnnotationConfigApplicationContext ,而web用AnnotationConfigWebApplicationContext
多个Context
我们可以设置多个上下文,这些上下文是树状继承结构。即包括管理自己的bean,父辈的bean,祖辈的bean,以此类推。我们可以使用一些公共的bean,也可以使用一些不同的隔离的bean。例如对某个web应用,普通用户和管理员用户,他们有不同也有相同的处理。
单一Context的设置
要正确启动Spring:
- 对于J2SE应用,在public static void main(String...)中通过代码启动
- 对于J2EE有两种方式:
- 使用XML的部署描述符进行配置,即在web.xml中
- 在javax.servlet.ServletContainerInitializer通过代码启动
本例,我们将通过deployment descriptor来启动单一上下文的spring。
web.xml设置
<?xml version="1.0" encoding="UTF-8"?>
<web-app ......>
... ...
<!-- 匹配采用最佳匹配,在后面将/匹配给spring的DispacherServlet,但我们会有一些静态的html,css,js,图片文件,需要访问,下面是确保这些静态资源的直接获取。-->
<!-- - default表示采用容器的缺省方式。-->
<!-- - 如果将这些静态资源都放入到/resource/中,这样就只需<url-pattern>/resource/*</url-pattern> -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/resource/*</url-pattern>
<url-pattern>*.css</url-pattern>
<url-pattern>*.js</url-pattern>
<url-pattern>*.png</url-pattern>
<url-pattern>*.gif</url-pattern>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<!-- Spring使用dispatcher Servlet将请求分派给controller。每一个DispatcherServlet实例有其自己的应用上下文,对应其ServletContext及ServletConfig。本例是单一上下文,故有且只有一个DispatchServelt。-->
<!-- DispatcherServlet要求在startup启动,有一个配置文件,通过contextConfigLocation属性来进行设置 -->
<servlet>
<servlet-name>springDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servletContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 注意,这里匹配使用/,而不是/* -->
<!-- 1) / : 进行所有的URL匹配,并同时允许Servlet容器的JSP机制来处理JSP请求 -->
<!-- 2) /* :会导致内部的jsp请求也匹配过来,这不是我们所需要的 -->
<!-- 如果我们匹配的是/do/*,DispatherServlet是从/do/后面开始匹配,根据二次匹配分派:-->
<!-- - 即我们在controller代码中不需要修改,相应的url为http://localhost:8080/chapter12/do/custom?name=wei,或者http://localhost:8080/chapter12/do/(匹配controller中的/) -->
<servlet-mapping>
<servlet-name>springDispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 可以使用distributable元素来告诉servlet/JSP容器,将在分布式Web容器中部署。 -->
<!-- To enable clustering of your web application you must tag it as distributable in the web.xml descriptor. -->
<distributable />
</web-app>
上下文设置:servletContext.xml
在servletContext.xml只servletContext的配置文件,管理它的beans,所以根是<beans>。
<?xml version="1.0" encoding="UTF-8"?>
<!-- 在单一上下文中,我们需要mvc和bean的schema。-->
<!-- 对于schemaLocation的设置,可以不带版本号,写成http://www.springframework.org/schema/mvc/spring-mvc.xsd,http://www.springframework.org/schema/beans/spring-beans.xsd。 对应的就是最新的版本,若schema能向下兼容,就无所谓。 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.6.xsd">
<!-- 允许在controller中使用@RequestMapping,@RequestBody, @RequestParam, @PathParam和@ResponseBody,这些在后面慢慢学习 -->
<mvc:annotation-driven />
<!-- 实例化我们编写的两个bean,一个是service的实现greetingServiceImpl,一个是controllerhelloController,同时将service的实现greetingServiceImpl注入到controller bean中作为greetingService属性 -->
<bean name="greetingServiceImpl" class="cn.wei.flowingflying.chapter12.GreetingServiceImpl" />
<bean name="helloController" class="cn.wei.flowingflying.chapter12.HelloController">
<property name="greetingService" ref="greetingServiceImpl"/>
</bean>
</beans>