Spring MVC

1.Spring技术体系

   


Spring MVC 主要组件

     1. DispatcherServlet 

               核心控制器,按照servlet标准定义,定义在web.xml中,所有请求先进入DispatcherServlet

      2.HandlerMapping

                  处理器映射,负责根据请求映射到不同Controller

       3.Controller

              处理器,负责接收请求及参数,调用业务组件Service/DAO进行处理,然后返回处理结果

        4. ModelAndView

               负责存储模型数据和视图名称

        5. ViewResolver

                视图解析器,根据ModelAndView中视图名找JSP,生成HTML

Sprig MVC 处理流程

       

    

 配置DispatcherServlet(web.xml)  

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

  • 配置HandlerMapping(applicationContext.xml)

    <bean id="handlermapping" 
    class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <props>
            <prop key="/hello.do">hellocontroller</prop>
        </props>
    </property>
    

  • 配置HelloController(applicationContext.xml)

    <bean id="hellocontroller"
     class="cn.xdl.controller.HelloController">
    </bean>

配置ViewResolver(applicationContext.xml)

<bean id="viewresolver" 
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>


Spring MVC注解配置

 1.框架可以采用xml配置和注解配置,平时混用,jar包中提供的组件采用XML定义;程序员定义的组件用注解置

 2.handlerMapping 可以使用RequestMappingHandlerMapping 替代SimpleUrlHandlerMapping组件   

SimpleUrlHandlerMapping工作

<bean id="handlermapping" 
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
    <props>
        <prop key="/hello.do">hellocontroller</prop>
        <prop key="/login.do">logincontroller</prop>
    </props>
</property> 

RequestMappingHandlerMapping工作

<bean id="handlermapping" 
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
</bean>
<bean id="handlermapping" 
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
</bean>

可以使用下面配置替代上面< bean>定义

<mvc:annotation-driven/>

在Controller组件方法前使用@RequestMapping("/hello.do")

POST中文乱码解决办法,Spring框架提供了一个CharacterEncodingFilter过滤器。内部执行了request.setCharacterEncoding("**"),配置在web.xml中

<!-- 解决post中文乱码过滤器 -->
<filter>
    <filter-name>characterfilter</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>
</filter>
<filter-mapping>
    <filter-name>characterfilter</filter-name>
    <url-pattern>*.do</url-pattern>
</filter-mapping>

RowMapper创建映射对象 ,SpringDAO 无法将查询到的结果映射成实体类对象,需要手动添加映射      

 RowMapper<Book> rowMapper = new BeanPropertyRowMapper<Book>(Book.class);

xml文件中定义c3p0连接池

<bean id="c3p0" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="user" value="SCOTT"></property>
    <property name="password" value="TIGER"></property>
    <property name="jdbcUrl" value="jdbc:oracle:thin:@locahost:1521:XE"></property>
    <property name="driverClass" value="oracle.jdbc.OracleDriver"></property>
</bean>

定义JdbcTemplate对象

<bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="c3p0"></property>
</bean>

Spring  MVC拦截器组件

      1.拦截器组件实现HandlerInterceptor接口,接口中有3个方法,分别在处理器执行前,执行后,请求处理额按笔响应输出前执行

public class CheckInterceptor implements HandlerInterceptor{

    //postHandle和afterCompletion省略

    public boolean preHandle(
        HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
        //检查是否登录,session是否有指定信息
        HttpSession session = request.getSession();
        Object user = session.getAttribute("user");
        if(user != null){//有登录信息
            return true;
        }else{
            response.sendRedirect("/spring_05/login.do");
            return false;
        }
    }

}

     2.  在spring中配置拦截器  

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/book/delete.do"/>
        <mvc:mapping path="/book/modify.do"/>
        <bean class="cn.xdl.interceptor.CheckInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

Spring MVC 异常处理

     当流程调用Controller,Service,Dao组件抛出异常后,Spring MVC会调用ExceptionResolver异常处理器处理,异常处理器可以自己定义,也可以使用内置的;

   1.内置异常处理器SimpleMappingExceptionResolver,xml文件中配置如下,即可         

 <bean id="handleException" 
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
    <props>   /*发生java.lang.Exception异常跳转到error.jsp*/
        <prop key="java.lang.Exception">error</prop>          
    </props>
</property>
  2.自定义ExceptionResolver组件

      编写实现类,实现HandlerExceptionResolver接口

public class MyExceptionResolver implements HandlerExceptionResolver{
    //注入异常类型和视图名
    private Properties exceptionMappings;
    //set注入方法
    public void setExceptionMappings(Properties exceptionMappings) {
        this.exceptionMappings = exceptionMappings;
    }

    @Override
    public ModelAndView resolveException(
        HttpServletRequest request, 
        HttpServletResponse response, 
        Object arg2,
        Exception ex) {
        ModelAndView mav = new ModelAndView();
        //根据ex类型封装成对应ModelAndView
        String className = ex.getClass().getName();
        String viewName = exceptionMappings.getProperty(className);
        if(viewName == null){
            viewName = "error";
        }
        System.out.println("className:"+className);
        System.out.println("viewName:"+viewName);
        mav.setViewName(viewName);
        return mav;
    }

}
    配置异常处理器

<bean id="handleException" 
    class="cn.xdl.exception.MyExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.NumberFormatException">error</prop>
        </props>
    </property>
</bean>

局部异常处理,ExceptionResolver都是全局范围处理,如果某个Controller异常需要特殊处理,可以使用@ExceptionHandler局部处理

@ExceptionHandler
public ModelAndView handlerException(Exception e){...}

Spring AOP 

    -切面(aspect)(追加什么功能)

            指的是在相同时机或者位置执行的相同处理。封装了共同功能的组件一般被称为切面组件,切面组件可以作用到其他组件上;

    - 切入点(pointcut)(给谁加功能),Spring提供了切入点表达式,用于指定目标组件及方法

        1.方法限定表达式

                 execution(修饰符? 返回类型 方法名(参数列表)throws异常?)

                        eg:execution(* cn.xdl.BookController.load*(..))    

                                execution(* load*(..))     execution(* cn.xdl..(..))

             2.类型限定表达式

                       within(包名.类型名)     eg: within(cn.xdl.BookController)

                  3.组件名称限定表达式

                     bean(id)  eg: bean(bookController)     bean(*Controller)

  • 通知(Advice)(什么时候加?)

    指定切入功能执行的时机。例如目标方法前执行、目标方法后执行、目标方法抛异常后、目标方法执行前和执行后等。

    • 环绕通知--目标方法前和后执行
    • 前置通知--目标方法前执行
    • 后置通知--目标方法后执行(无异常执行)
    • 异常通知--目标方法抛异常后执行
    • 最终通知--目标方法后执行(有无异常都执行)
  • 目标(Target)

    指的是需要追加功能的组件。

 

   AOP案例:服务调用日志记录

        需求:每一次调用服务,将调用时间,执行时间记录下来

      1.加什么功能?

           将调用时间,执行时间记录下来

       2.给谁加?

         bean(bookController)/within(cn.xdl.controller.BookController)

        3.什么时间加?

           在目标方法前和后都加逻辑(环绕通知)

         4.实现过程

              - 在spring中开启aop配置

                    <aop:aspectj-autoproxy/>

                - 编写watchBean组件             

@Component
@Aspect//指定该组件是切面组件
public class WatchBean {

        @Around("within(cn.xdl.controller.BookController)")
        public Object execute(ProceedingJoinPoint pjp) throws Throwable{
            //记录调用时间、执行时间、调用服务方法名
            //目标方法之前调用逻辑
            Date callTime = new Date();//1.获取调用时间
            String methodName = pjp.getSignature().getName();//获取服务方法名
            StopWatch watch = new StopWatch();
            watch.start();//开始计时
            Object obj = pjp.proceed();//执行目标方法
            //目标方法之后调用逻辑
            watch.stop();//停止计时
            long execTime = watch.getTotalTimeMillis();//3.获取执行时间
            System.out.println("调用了"+methodName
                +"服务,调用时间为:"+callTime+" 执行时间为:"+execTime);
            return obj;
        }

    }

Spring AOP通知

  1.前置/后置/最终/异常/环绕通知,其中后置通知是指在目标方法后加入追加功能,如果目标方法抛异常则不会追加,最终通知则无论是否抛异常,都会追加功能;

      在目标方法前切入追加功能。方法格式如下:

      @Before("切入点表达式")   

@AfterReturning("切入点表达式")

@After("切入点表达式")

@AfterThrowing(...)

@Around("within(cn.xdl.controller.BookController)") public Object execute(ProceedingJoinPoint pjp) throws Throwable{

案例:采用AOP实现异常处理

   需求:当服务调用中发生异常,将异常记录到日志文件中

@Component
@Aspect
public class ExceptionBean {

    @AfterThrowing(throwing="ex",pointcut="within(cn.xdl.controller..*)")//方法抛异常执行
    public void handle(Exception ex){
        try {
            FileWriter fw = new FileWriter("E:\\spring_07_error.log", true);
            PrintWriter out = new PrintWriter(fw);
            out.println("-----------发生了异常------------");
            out.println("-异常类型:"+ex);
            out.println("-发生时间:"+new Date());
            out.println("-异常详情:");
            StackTraceElement[] stes = ex.getStackTrace();
            for(StackTraceElement s : stes){
                if(s.toString().contains("cn.xdl")){
                    out.println(s.toString());
                }
            }
            out.flush();
            out.close();
            fw.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
案例2:AOP实现原理(动态代理模式)

原理:Spring容器配置AOP,容器返回的BookController对象实际是一个动态代理技术生成子类对象(CGLIB技术)。动态代理类将BookController所有方法重写,在重写时加入BookController功能和切入的新功能(切面组件)。

  • 根据现有组件创建代理对象

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(bean.getClass());//将bean类型做父类
    enhancer.setCallback(this);//注册回调函数
    return enhancer.create();
    
  • 每次调用代理对象方法,都会采用回调机制调用原组件方法,可以在回调方法中做扩展操作

    public class CglibProxyFactoryBean implements MethodInterceptor{
    
        public Object intercept(
            Object obj, Method method, Object[] args, MethodProxy arg3) throws Throwable {
        //切入目标方法前面执行的逻辑
        System.out.println("回首2017");
        Object retval = method.invoke(target, args);//调用目标组件对象的method方法
        //切入目标方法后面执行的逻辑
        System.out.println("展望2018");
        return retval;
        }
    
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值