Spring | SpringMVC
1) Spring是一个IOC(DI)和AOP容器框架。
1) Spring的优良特性
依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。
面向切面编程:Aspect Oriented Programming——AOP
一站式:在IOC和AOP的基础上可以整合各种企业应用的开源框架和优秀的第三方 类库(实际上Spring 自身也提供了表述层的SpringMVC和持久层的Spring JDBC)。
IOC(Inversion of Control):反转控制
应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资源;
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式:反转了资源的获取方向——改由容器主动的将资源推送给需要的组件,开发人员不需要知道容器是如何创建资源对象的,只需要提供接收资源的方式即可
DI(Dependency Injection):依赖注入
IOC的另一种表述方式:即组件以一些预先定义好的方式(例如:setter 方法)接受来自于容器的资源注入。相对于IOC而言,这种表述更直接。
IOC 描述的是一种思想,而DI 是对IOC思想的具体实现.
Bean配置解释
<bean>: 让IOC容器管理一个具体的对象.
id: 唯一标识
class: 类的全类名. 通过反射的方式创建对象.
Class cls = Class.forName("com.atguigu.spring.helloWorld.Person");
Object obj = cls.newInstance(); 无参数构造器
<property>: 给对象的属性赋值.
name: 指定属性名 ,要去对应类中的set方法.
value:指定属性值
获取Bean的方式
1) 从IOC容器中获取bean时,除了通过id值获取,还可以通过bean的类型获取。但如果同一个类型的bean在XML文件中配置了多个,则获取时会抛出异常,所以同一个类型的bean在容器中必须是唯一的。
//1.创建IOC容器 ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.获取HelloWorld对象;唯一标示的id为“Hi” HelloWorld bean = (HelloWorld) ioc.getBean("Hi"); 或者这种方式来获取Bean: HelloWorld helloWorld = ioc.getBean(HelloWorld. class); 或者可以使用另外一个重载的方法,同时指定bean的id值和类型 HelloWorld helloWorld = cxt.getBean(“helloWorld”,HelloWorld. class); //3.调用HelloWorld中的方法 bean.sayHello();
给bean的属性赋值(普通类型的值、引用类型的值)
<!-- 给bean的属性赋值,(普通类型的值、引用类型的值)
1.通过vlaue属性或vlaue子标签(了解) 2.通过ref属性或ref子标签(了解)
-->
<bean id="employee" class="com.atguigu.spring.entities.Employee">
<property name="id" value="1"></property>
<property name="lastName">
<value>kk</value> 可使用<value>子标签来赋值;
</property>
<property name="email" value="kk@qq.com"> </property>
<property name="salary" value="10000"> </property>
<!-- <property name="deptId" value="2"> </property> -->
<property name="dept" ref="department"></property> 有引用数据类型的值
</bean>
配置Department,再将配置好的Department注入到Employee中(使用ref)
<bean id="department" class="com.atguigu.spring.entities.Department">
<property name="id" value="2"></property>
<property name="name" value="设计"></property>
</bean>
引用外部属性文件
<!-- 方式一:直接配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
<!-- 方式二: 引入外部属性文件以properties的格式 -->
<context:property-placeholder location="classpath:druid.properties"/>
<!-- 通过引入外部配置文件引入数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="initialSize" value="${jdbc.initialSize}"></property>
<property name="minIdle" value="${jdbc.minIdle}"></property>
<property name="maxActive" value="${jdbc.maxActive}"></property>
<property name="maxWait" value="${jdbc.maxWait}"></property>
</bean>
创建properties属性文件(位于src/main/resources);
在xml中引入context名称空间;
指定properties属性文件的位置;从properties属性文件中引入属性值
<!-- 指定properties属性文件的位置 --> <!-- classpath:xxx 表示属性文件位于类路径下 --> <context:property-placeholder location="classpath:jdbc.properties"/>
基于注解配置Bean
1) 手动装配:以value或ref的方式明确指定属性值都是手动装配。
2) 自动装配:根据指定的装配规则,不需要明确指定,Spring自动将匹配的属性值注入bean中。
相对于XML方式而言,通过注解的方式配置bean更加简洁和优雅,而且和MVC组件化开发的理念十分契合,是开发中常用的使用方式。
1) 普通组件:@Component
标识一个受Spring IOC容器管理的组件
2) 持久化层组件:@Repository
标识一个受Spring IOC容器管理的持久化层组件
3) 业务逻辑层组件:@Service
标识一个受Spring IOC容器管理的业务逻辑层组件
4) 表述层控制器组件:@Controller
标识一个受Spring IOC容器管理的表述层控制器组件
5) 组件命名规则
①默认情况:使用组件的简单类名首字母小写后得到的字符串作为bean的id
②使用组件注解的value属性指定bean的id
注意:事实上Spring并没有能力识别一个组件到底是不是它所标记的类型,即使将@Respository注解用在一个表述层控制器组件上面也不会产生任何错误,所以 @Respository、@Service、@Controller这几个注解仅仅是为了让开发人员自己明确当前的组件扮演的角色。
Spring Web MVC (SpringMVC)
Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口
C(controler ,处理用户请求的,与servlet功能是一样的,请求先到达C层;)
M(model模型控制器(业务模型和数据模型))
V(View视图,视图解析器来渲染视图)
请求到达C之后要去拿Model,它再返回给C数据,C再找View(数据以什么方式进行呈现给用户),V处理完之后把页面给C,最后它给用户。
表现层(出来用户请求的)、业务逻辑层(出来业务逻辑的)、持久化层(DAO连接数据库)。
SpringMVC在这个基础上又加了一个前端控制器(配置在web.xml中);它负责分配,让哪个C去处理请求;
请求先到前端控制器它先拦截,由它来分配。
) 在web.xml中配置DispatcherServlet(前端控制器)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<!-- 配置前端控制器|核心控制器 DispatcherServlet -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value> 文件位置,服务器解析xml时来造这个对象,
</init-param>
<load-on-startup>1</load-on-startup> 服务器一启动就把对象造好了,不用发请求
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern> /是为了覆盖tomcat服务器中的xml,为了替代default它拦截的请求(/它是除了jsp不拦截其他都拦截后交给它处理);
</servlet-mapping> //替换它,替换它拦截的请求交给我处理; jsp有专门的jsp处理
<!-- 通过过滤方式配置中文,后端显示中文不会乱码 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
<?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" 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.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 设置自动扫描的包 --> <context:component-scan base-package="com.atguigu.springmvc"></context:component-scan> <!-- 配置视图解析器来渲染视图 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 配置前缀 --> <property name="prefix" value="/WEB-INF/views/"></property> <!-- 配置后缀 --> <property name="suffix" value=".jsp"></property> </bean> <!-- 处理静态资源,如加载juqery等 --> <mvc:default-servlet-handler/> <!-- 配置了处理静态资源之后,Handler中的@RequestMapping注解就失效了,此时必须配置以下标签 --> <mvc:annotation-driven></mvc:annotation-driven> </beans>
前缀 + 返回值 + 后缀,拼接起来 /WEB-INF/views/success.jsp
创建处理器(让当前类成为处理器,加@Controller注解)
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="${pageContext.request.contextPath}/script/jquery-1.7.2.js"></script>
<script type="text/javascript">
/* alert($); */
</script>
</head>
<body>
<a href="${pageContext.request.contextPath }/hello">Hello SpringMVC</a>
<br>
<a href="${pageContext.request.contextPath }/testValue">testValue</a>
<br>
<a href="${pageContext.request.contextPath }/testMethod">testMethod</a>
<form action="${pageContext.request.contextPath}/testMethod" method="post">
<input type="submit" value="提交">
</form>
<a href="${pageContext.request.contextPath}/testRequestParam?username=admin">test RequestParam</a>
<h2>测试入参POJO</h2>
<form action="${pageContext.request.contextPath }/testPOJO">
员工编号:<input type="text" name="id"><br>
员工姓名:<input type="text" name="lastName"><br>
员工邮箱:<input type="text" name="email"><br>
员工薪水:<input type="text" name="salary"><br>
部门编号:<input type="text" name="dept.id"><br>
部门名字:<input type="text" name="dept.name"><br>
<input type="submit" value="TestPOJO提交">
</form>
<h3>测试入参为原生SevletAPI</h3>
<form action="${pageContext.request.contextPath}/testServletAPI" method="post">
员工姓名:<input type="text" name="username">
<input type="submit" value="TesetServletAPI">
</form>
<!-- 转发 -->
<a href="${pageContext.request.contextPath }/testModelAndView">ModelView</a><br>
<a href="${pageContext.request.contextPath }/testMap">Map</a><br>
<!-- 重定向 -->
<a href="${pageContext.request.contextPath }/testRedirect">Redirect</a>
</body>
</html>
@Controller
public class SpringMVCHandler {
public static final String SUCCESS = "success";
/* @RequestMapping处理请求映射;注解中的属性
* 1.value -用来设置要映射的请求地址
-该属性的类型是一个String类型的数组,如果映射的请求地址(必须携带请求参数params)只有一个那么大括号可以省略, 而且value属性名也可以省略不写
2.method
-用来设置要映射的请求方式 -如果没有指定改属性如post,那么只看处理的请求地址,不管请求方式,不是默认出来get请求*/
//测试value
@RequestMapping(value={"/testValue", "testValue2"})
public String testValue() {
System.out.println("测试value");
return SUCCESS;
}
//测试method
@RequestMapping(value="/testMethod" ) 可加请求参数params={"username=admin", "age=18"}
public String testMethod() {
System.out.println("测试method");
return SUCCESS;
/*点击超链接是get请求*/
}
//测试post请求
@RequestMapping(value= "/testMethod", method=RequestMethod.POST)
public String testPost() {
System.out.println("测试post");
return SUCCESS;
}
/* @RequestParam注解 -用来映射请求参数,如果Handler方法的入参的参数名和请求参数的参数名一致,那么该注解可以不写(不建议这样)
value属性: -用来设置请求参数的参数名 required属性: -用来设置该请求参数是否是必须的,默认是true,是必须的
defaultValue属性: -用来设置一个默认值,如果没有携带该请求参数那么将使用此默认值*/
@RequestMapping("/testRequestParam")
public String testRequestParam(@RequestParam("username") String username,
@RequestParam(value="age", required=false, defaultValue="0") int age) { //或者Integer
System.out.println("用户名是:" + username);
System.out.println("年龄是:" + age);
return SUCCESS;
}
//Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配, 自动为该对象填充属性值,支持级联属性
@RequestMapping("/testPOJO")
public String testPOJO(Employee employee) {
System.out.println("员工信息为:" + employee);
return SUCCESS;
}
/*SpringMVC 的 Handler 方法可以接受以下ServletAPI 类型的参数 1) ★HttpServletRequest 2)* ★HttpServletResponse
3) ★HttpSession */
@RequestMapping("/testServletAPI")
public String testSevletAPI(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter("username");
System.out.println("用户名是:" + username);
return SUCCESS;
}
//处理响应数据方法一:将Handler的方法的返回值设置为ModelAndView
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView() {
//①创建对象
ModelAndView mv = new ModelAndView();
Employee employee = new Employee(2, "嘿嘿", "hei@qq.com", 20000.3, null);
//②添加数据模型
mv.addObject("emp", employee);
//③设置视图名
mv.setViewName("success");
return mv;
}
//处理响应数据二:
/*方法的返回值还是String类型,在Handler的方法入参中传入Map、Model或ModelMap
不管在Handler的方法中传入Map、Model还是ModelMap,SpringMVC都会转换为一个ModelAndView对象*/
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map) {
Employee employee = new Employee(1, "smile", "sl@126.com", 20000.01, null);
map.put("emp", employee); //将模型数据放到map中,最终会放到request域中
return SUCCESS;
}
//重定向
@RequestMapping("/testRedirect")
public String testRedict() {
System.out.println("开始重定向");
return "redirect:/redirect.jsp";
}
}
Spring与SpringMVC需不需要整合? * 不整合 * 1.将所有的配置都配置到SpringMVC的配置文件中 * 2.将Spring的配置文件通过import标签引入到SpringMVC的配置文件中 * ★整合 * Spring的配置文件中管理Service、Dao、数据源、事务以及与其他框架的整合 * SpringMVC的配置文件管理Handler、视图解析器、处理静态资源等 * 问题一: * IOC容器如何初始化? * Java工程:new ClassPathXmlApplicationContext("beans.xml"); * Web工程:在web.xml文件中配置ContextLoaderListener这个监听器 * 问题二: * Handler和Service被创建了两次? * 让Spring不扫描Handler * 让SpringMVC只扫描Handler
springmvc.xml
<!-- 组件扫描 -->
<!-- 子标签context:include-filter:用来设置只扫描那个包下的类
-要让此标签生效,必须将父标签的use-default-filters的属性值改为false -->
<context:component-scan base-package="com.atguigu.ss" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
beans.xml
<!-- 设置自动扫描的包 -->
<context:component-scan base-package="com.atguigu.ss">
<!-- 子标签context:exclude-filter:用来设置不扫描那个包下的类
如果type的值是annotation,那么expression的值是注解的全类名
如果type的值是assignable,那么expression的值是接口或实现类的全类名 -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan >
web.xml
<!-- 前端控制器 -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 配置ContextLoaderListener监听器; Web工程-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>