声明式事务、SpringMVC详解

声明式事务

  开发者采用配置的方式来实现事务的控制,业务代码和事务代码实现解耦合,使用的就是上一篇的AOP思想。
  都需要定义一个事务管理器,都需要导入spring-aop和aspectjweaver两个jar包

事务的传播行为

事务传播行为指的就是当一个业务方法被另一个业务方法调用时,应该如何进行事务控制。
业务层A方法,调用业务层B方法【主要角色】

* REQUIRED【必须】默认值 运行的时候必须有事务
A方法调用B方法,如果A方法没有事务,B方法创建一个事务,如果A方法有事务,那么B方法直接使用A方法的事务控制
* SUPPORTS【支持】运行的时候 有就用 没有就不用
A方法调用B方法,如果A方法没有事务,B方法也没有事务,如果A方法有事务,那么B方法直接使用A方法的事务控制

1.xml配置声明式事务

需求
​ 使用spring声明式事务控制转账业务。
步骤分析:

在applicationContext.xml中

  1. 配置事务管理器 因为dao使用的JDBCTemplate,所以事务管理器为:DataSourceTransactionManager,注入连接池
  2. 定义事务的运行状态,通过tx标签配置
    就是给某种方法设置隔离级别,传播行为,是否只读,超时时间等
  3. aop配置,给那些切点配置spring提供好的事务通知.

db.propeties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/springtest
jdbc.username=root
jdbc.password=1234

applicationContext.xml

	<context:property-placeholder location="db.properties"/>
    <context:component-scan base-package="com.llz"/>

    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置jdbcTempalte-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--配置事务管理器,id建议大家使用transactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!--注入数据源-->
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--tx:advice标签配置运行规则
            给某种方式设置隔离级别,传播行为,是否只读,超时时间
            id属性:起个名字,待会用
            transactionManager属性:指定使用那个事务管理器,若事务管理器的名字为transactionManager的话,此属性可以省略
    -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!--以find开头的方方法,使用默认的隔离级别,使用supports传播行为,只读,超时时间为默认值:永不超时-->
        <tx:method name="find*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true" timeout="-1"/>
        <!--其他方法,使用默认的属性,用默认的隔离级别,默认传播行为,不是只读事务,超时时间为默认值-->
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<!--aop配置-->
<aop:config>
    <!--切入点-->
    <aop:pointcut id="pc" expression="execution(* com.llz.service..*.*(..))"/>
    <!--切面,使用spring已定义好的通知类-->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
</aop:config>

2.注解+xml配置声明式事务

步骤分析:

  1. 修改上面的applicationContext.xml
    • 删除事务控制的tx标签和aop标签
    • 添加事务的注解支持
  2. 在service类上或者service中方法上添加注解@Transactional
    • 可以通过注解的属性配置隔离级别,传播行为,是否只读,超时时间
<!--开启事务注解支持-->
 <tx:annotation-driven transaction-manager="transactionManager"/>

在这里插入图片描述
注意:若使用注解的话,千万记住要给每个service或者service中的方法添加注解

3.纯注解(了解即可,项目上一般不会使用)

步骤分析:

  1. 编写配置类 SpringConfig,添加注解,替代applicationContext.xml
    • 声明注解是一个配置类
    • 组件扫描
    • 加载properties配置文件
    • 事务注解支持
    • 创建数据源加入spring管理
    • 创建jdbcTemplate加入spring管理
    • 创建事务管理器,加入spring管理

主配置类:

@Configuration
@ComponentScan("com.llz")
@PropertySource("classpath:db.properties")
@EnableTransactionManagement//开启事务注解支持
@Import({DaoConfig.class,ServiceConfig.class})//引入其他的配置类
public class SpringConfig {
}

其他配置类:

public class DaoConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    /*创建数据源,加入spring管理*/
    @Bean
    public DataSource createDS(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }

    /*创建jdbcTemplate,加入spring管理*/
    @Bean
    public JdbcTemplate createJdbcTemplate(DataSource dataSource){
        return  new JdbcTemplate(dataSource);
    }
}
public class ServiceConfig {
    /*创建事务管理器*/
    @Bean
    public PlatformTransactionManager createTXManager(DataSource dataSource){
        return  new DataSourceTransactionManager(dataSource);
    }
}

SpringMVC

1.简介

  springMVC是按照MVC设计模式开发的轻量级web框架,他也是spring家族的一部分。
​  springMVC封装了servlet公共的特性,使开发者只需要关注业务的私有特性,来提高开发效率。
在这里插入图片描述
  要想处理公共的特性,应该能获取到request和response对象(前端控制器).谁能获取到这两个对象

  • servlet:例如springmvc使用DispatcherServlet
  • filter:例如struts2使用StrutsPrepareAndExecuteFilter
     使用springmvc的时候,需要先配置好前端控制器,然后就可以使用普通javabean处理业务请求

快速入门

在index.jsp上有一个连接(/springmvc/hello),点击连接,在控制台打印一句话,转发到/WEB-INF/pages/success.jsp

步骤分析

  1. 新建web项目,导入依赖(servlet,jsp,spring-webmvc)
  2. 编写index和success.jsp
  3. 编写一个普通的类 例如:HelloController
    • 编写一个普通的方法,例如:sayHello
      • 返回值string类型:目前就要转发的路径
    • 在类上添加注解@Controller,交给springmvc容器管理
    • 在方法上添加注解@RequestMapping(“hello”),将请求的路径和目标方法形成映射关系
  4. 在resources编写springmvc的核心配置文件,名字随意,建议叫springmvc.xml
    • 组件扫描
    • 开启springmvc的注解支持
    • 配置视图解析器
  5. 在web.xml配置前端控制器
    • 配置DispatcherServlet
      • 配置springmvc核心配置文件的路径
      • 配置servlet的加载时机 load-on-startup
      • 配置servlet的映射路径 /
  6. 测试

代码实现

<dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.5.RELEASE</version>
    </dependency>

controller类:

@Controller
public class A_HelloController {

    @RequestMapping("hello")
    public String sayHello(){
        System.out.println("收到了请求");
        //配置了视图解析器之后,返回的字符串就是转发的视图名称
        return "success";
        //return "/WEB-INF/pages/success.jsp";
    }
}

springmvc.xml:

<!--开启组件扫描-->
    <context:component-scan base-package="cn.it.web"/>
    <!--开启mvc注解支持-->
    <mvc:annotation-driven/>
    <!--配置视图解析器对象-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--配置前缀-->
        <property name="prefix" value="/WEB-INF/pages/"/>
        <!--配置后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

web.xml

<!--配置springmvc的前端控制器-->
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--指定springmvc核心配置文件路径-->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!--修改servlet的初始化时机-->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<!--配置字符编码过滤器(post请求中文过滤器)-->
<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <!--指定post请求的编码-->
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

执行流程
在这里插入图片描述

SpringMVC组件概述

SpringMVC框架执行流程(重点)

在这里插入图片描述
项目启动时:

  1. dispatcherServlet对象就会随着项目的启动完成创建操作
  2. 读取核心配置文件,创建springmvc容器对象
  3. 扫描cn.it.web包下所有的带有@Component及其衍生注解的类,创建对象,加入springmvc容器中
  4. 扫描有@RequestMapping的方法,将访问路径和类名+方法形成映射关系
  5. 创建视图解析器对象,加入到springmvc容器中

请求来的时候:

  1. 当请求来的时候,路径为:/hello,前端控制器就会收到这个请求
  2. 前端控制器就找到处理器映射器,问它:/hello对应是哪个类中哪个方法. 处理器映射器返回:要执行的A_HelloController中的sayHello方法,没有拦截器
  3. 前端控制器再找到处理器适配器,告诉它:去执行A_HelloController中的sayHello方法.
  4. 处理器适配器获取到A_HelloController对象(处理器),让其调用它的sayHello方法.
  5. 处理器执行后,返回字符串"success".
  6. 处理器适配器拿到字符串之后,将返回的数据和字符串封装到ModelAndView对象中,返回给前端控制器
  7. 前端控制器拿到ModelAndView之后,获取视图字符串"success",找到视图解析器,问:success对象的是那个jsp(视图)
  8. 视图解析器拿到"success"之后,拼接前缀,字符串,后缀,生成视图对象(物理视图),返回给前端控制器
  9. 前端控制器拿到物理视图之后,将model放入指定域中,转到物理视图(success.jsp)
  10. jsp执行后,生成html代码.将html代码返回给前端控制器
  11. 前端控制器将html代码写回给浏览器

三大组件

处理器映射器、处理器适配器、视图解析器

* 前端控制器
整个流程控制的中心,由它调用其它组件处理用户的请求
* 处理器映射器(mvc支持注解)
负责将url路径和方法上的路径产生映射关系,返回处理器执行链
* 处理器适配器(mvc支持注解)
根据执行路径查找多个处理器中的某一个方法,执行业务逻辑,返回ModelAndView
* 视图解析器
将逻辑视图解析(例如:success)为view对象(真实资源文件对象)

请求常用的注解解析

@Controller

  • 作用在web层的类上,将类对应的对象加入springmvc容器中(IOC)
    @RequestMapping
  • 主要作用:配置路径和方法的映射. 该注解可以作用类上和方法上
  • 常用或常见属性:
    • value属性:
      • 若类上也有此注解,类上的value就是一级路径,方法上的路径就是二级路径.最终访问路径就是一级路径+二级路径.方便团队模块开发
    • name属性:给处理器起个名字
    • params属性:规定请求的路径中必须出现的参数内容,若没有报400异常
    • method属性:规定处理哪种请求方式
@Controller
@RequestMapping("mapping")//mapping就是一级路径
public class B_ReqeustMappingController {
 /*
     * name属性:给处理器起个名字
     * params属性:规定请求的路径中必须出现的参数内容,若没有报400异常
     */
    @RequestMapping(value = "test1",name = "测试name属性",params = "username")
    public String test1(){
        System.out.println("收到了请求");
        return "success";
    }

    /*
     * method属性:规定处理哪种请求方式,只处理get和post
     */
    @RequestMapping(value = "test2",method = {RequestMethod.POST,RequestMethod.GET})
    public String test2(){
        System.out.println("收到了请求");
        return "success";
    }
}

@RequestParam

  • 主要作用:当请求参数和方法参数名称不一样的时候,将请求的参数和方法参数形成映射关系. 它还可以设置参数的默认值
  • value属性:将请求参数的数据绑定到方法中某个参数上
    defaultValue属性:给参数设置默认值.当此参数没有值的时候就会使用默认值
    
@RequestMapping("anno")
public class D_AnnoController {
    /*
        @RequestParam
            value属性:将请求参数的数据绑定到方法中某个参数上
            defaultValue属性:给参数设置默认值.当此参数没有值的时候就会使用默认值
     */
    @RequestMapping(value = "test1")
    public String test1(@RequestParam(value="pageNumber") int pageNum, @RequestParam(defaultValue = "5") int pageSize){
        System.out.println(pageNum+"-"+pageSize);
        return "success";
    }
}    

SpringMVC的响应

1.响应方式介绍

方法的返回值:

  • string
    • 默认就是转发
    • 使用关键字声明转发还是重定向
  • void
    • 一般就是使用servlet原生的api进行操作,在文件下载中常用
  • modelAndView
    • 放置数据到域中,转发或者重定向都可以

String返回

a.默认方式
就是转发操作.若想往request域中存放数据,可以通过原生的servlet方式操作或者springmvc中的方式进行操作

  • springmvc方式中,可以通过map、modelMap或者model都可以
//默认转发
@RequestMapping("test1")
public String test1(HttpServletRequest request, Map map, ModelMap modelMap, Model model){
    //往request域中存放数据
    request.setAttribute("requestKey",1);
    map.put("mapKey",2);
    modelMap.put("modelMapKey",3);
    model.addAttribute("modelKey",4);
    return "success";
}

b.转发和重定向
  可以在返回值前面加上关键字声明转发还是重定向,一旦使用了关键字,就不再使用视图解析器

  • forward: 转发 后面跟上就是转发的内部路径
  • redirect: 重定向
    • 站内资源 后面跟上内部路径
    • 站外资源 后面跟上url
//关键字转发
@RequestMapping("test2")
public String test2(Map map){
    map.put("mapKey","关键字转发过来的数据");
    return "forward:/WEB-INF/pages/success.jsp";
}

//关键字重定向
@RequestMapping("test4")
public String test4(){
    return "redirect:http://www.baidu.com";
}

c.void返回
一般就是使用原生的api做文件下载操作.也不走视图解析器

@Controller
@RequestMapping("void")
public class B_VoidController {
    //void返回值做转发
    @RequestMapping("test1")
    public void test1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute("requestKey","void转过的数据");
        request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
    }

    //void返回值做重定向
    @RequestMapping("test2")
    public void test2(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.sendRedirect(request.getContextPath()+"/html/1.html");
    }
}

d.ModelAndView返回

方式一:在方法中创建对象
方式二:在方法的参数上声明对象

@Controller
@RequestMapping("mv")
public class C_ModelAndViewController {

    @RequestMapping("test1")
    public ModelAndView test1(ModelAndView mv){
        //往域中存放数据
        mv.addObject("modelKey","mv转发过来的数据");

        //设置转发的路径
        mv.setViewName("success");
        return mv;
    }

    @RequestMapping("test2")
    public ModelAndView test2(){
        ModelAndView mv = new ModelAndView();
        //往域中存放数据
        mv.addObject("modelKey","mv转发过来的数据");
        //设置转发的路径
        mv.setViewName("forward:/WEB-INF/pages/success.jsp");
        return mv;
    }
}

@RequestBody

将请求的json数据封装成指定对象

@ResponseBody

将方法的返回值转成json字符串写回浏览器

在这里插入图片描述

@RequestMapping("test2")
//RequestBody : 将请求的json数据封装成指定对象
//ResponseBody : 将方法的返回值转成json字符串写回浏览器
@ResponseBody
public Map test2(@RequestBody User user, HttpServletResponse response) throws IOException {
    System.out.println(user);
    Map map = new HashMap();
    map.put("success",true);
    map.put("msg","用户名:"+user.getUsername());
    return map;
}

RESTful(重要)

restful是一种软件架构的设计风格。主要用于客户端和服务器交互的软件架构。如果我们软件设计使用了此风格,咱们的架构层次更加分明,简洁、易于缓存…
通过请求路径+请求方式来简化路径编写,确定要指定的是那个controller

  • 查询操作 请求路径:/user/id值 请求方式:get
  • 删除操作 请求路径:/user/id值 请求方式:delete
  • 保存操作 请求路径:/user 请求方式:post
  • 更新操作 请求路径:/user 请求方式:put

浏览器提交的方式只能为二种:get、post
使用ajax发送不同的请求方式即可.

spring提供的注解:

  • @PathVariable(“uid”) :获取请求路径上变量赋值给方法参数
  • @GetMapping(“路径”):处理get请求的requestMapping
  • @PostMapping(“路径”)
  • @DeleteMapping(“路径”)
  • @PutMapping(“路径”)
  • @RestController 一个顶俩(@Controller和@ResponseBody)
<input type="button" value="f_查询" id="btn_get">
<input type="button" value="f_删除" id="btn_delete">
<input type="button" value="f_保存" id="btn_post">
<input type="button" value="f_更新" id="btn_put">
<%--导入jquery.js--%>
<script src="js/jquery-2.2.3.min.js"></script>
<script>
    /*restful*/
    //查询
    $("#btn_get").click(function () {
        $.ajax({
            url:"${pageContext.request.contextPath}/user/10",
            type:"get",
            success:function (resp) {
                if (resp.success) {
                    alert(resp.msg);
                }
            }
        })
    });

    //删除
    $("#btn_delete").click(function () {
        $.ajax({
            url:"${pageContext.request.contextPath}/user/9",
            type:"delete",
            success:function (resp) {
                if (resp.success) {
                    alert(resp.msg);
                }
            }
        })
    });

    //保存
    $("#btn_post").click(function () {
        $.ajax({
            url:"${pageContext.request.contextPath}/user",
            type:"post",
            data:"username=tom&age=18",
            success:function (resp) {
                if (resp.success) {
                    alert(resp.msg);
                }
            }
        })
    });

    //更新
    $("#btn_put").click(function () {
        $.ajax({
            url:"${pageContext.request.contextPath}/user",
            type:"put",
            data:"username=jack&age=19",
            success:function (resp) {
                if (resp.success) {
                    alert(resp.msg);
                }
            }
        })
    });
</script>
//@Controller
//@ResponseBody //可以作用在类上和方法上
@RestController //一个顶俩(@Controller和@ResponseBody )
public class F_UserController {
    /*
     * @PathVariable:将路径上的指定名称变量绑定到方法的参数上
     * @GetMapping:处理get请求RequestMapping
     * @DeleteMappping:处理delete请求RequestMapping
     * @PutMapping:处理put请求RequestMapping
     * @PostMapping:处理post请求RequestMapping
     */
    //@RequestMapping(value="user/{uid}",method = RequestMethod.GET)
    @GetMapping("user/{uid}")//相当于@RequestMapping(value="user/{uid}",method = RequestMethod.GET)
    //@ResponseBody
    public Map findById(@PathVariable("uid") int id){
        System.out.println(id);
        Map map = new HashMap();
        map.put("success",true);
        map.put("msg","获取指定的用户,id为:"+id);
        return map;
    }

    @DeleteMapping("user/{uid}")
    public Map deleteById(@PathVariable("uid") int id){
        System.out.println(id);
        Map map = new HashMap();
        map.put("success",true);
        map.put("msg","删除指定的用户,id为:"+id);
        return map;
    }

    @PostMapping("user")
    public Map save(User user){
        System.out.println(user);
        Map map = new HashMap();
        map.put("success",true);
        map.put("msg","保存用户,username:"+user.getUsername());
        return map;
    }

    @PutMapping("user")
    public Map update(User user){
        System.out.println(user);
        Map map = new HashMap();
        map.put("success",true);
        map.put("msg","修改用户,username:"+user.getUsername());
        return map;
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值