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: 类的全类名. 通过反射的方式创建对象.

cls

obj

                            <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>