SpringMVC(四)——跨域问题、异常处理、自定义视图、事务

本文详细介绍了Web开发中的跨域问题及其产生的原因,包括同源策略的限制和浏览器对AJAX请求的处理。针对跨域问题,文章提出了SpringMVC的CORS解决方案,包括使用@CrossOrigin注解和CorsFilter,并讲解了携带Cookie的处理。此外,还提到了JSONP作为一种绕过同源策略的方法。最后,文章提及了SpringMVC的异常处理和自定义视图,以及事务管理的相关配置和传播机制。
摘要由CSDN通过智能技术生成

跨域问题

同源策略

同源策略是一个重要的web安全策略,只有协议、域名、端口三个全部一致才是同源的,当有一个不同时,浏览器对服务器的访问就可能面临一个跨域问题

什么时候会存在跨域问题

当不同源时,也并非一定会面临跨域问题,比如当表单提交、连接跳转等不会出现跨域问题;只有当ajax请求时,才会出现跨域问题所以出现跨域问题的条件是:ajax请求、不同源

跨域后面临的问题

  1. 浏览器无法接收响应
  2. 服务器无法判断浏览器的身份,每次的session都会新建

解决方式

SpringMVC—CORS

流程
在这里插入图片描述

对于get请求,浏览器发送之后经由服务器处理,当服务器响应后检查响应头的Access-Control-Allow-Origin是否有自己,如果没有则不会接收请求;对于post请求,浏览器会先发送一个Options请求,用于查看服务器的响应中是否有自己,如果有才会发送post请求。这是因为post请求一般是为了提交数据,为了防止直接被服务器执行

办法

  1. 在控制器使用@CrossOrigin注解,在前端ajax请求时需要在xhrFields中设置一个withCredentails为true带去一个凭证,如Cookie;并指定@CrossOrigin的value属性为前端的站点,allowCredentials为true来同意接收凭证
  2. 使用CorsFilter,该过滤器的主要目的就是为了将Access-Control-Allow-Origin设置为请求方的站点;两个方式效果相同,只是配置方式和作用域的区别(注解用于单处理器,过滤器用于所有处理器)
$.ajax({
	url:"http://localhost:8081/user/register",
	type:"get",
	dataType:"json",
	xhrFields:{
		withCredentials:true,
	},
	data:{
		name:function(){
			return $("#name").val();
		}
	}
})
@Controller
@RequestMapping("user")
@CrossOrigin(value = "http://localhost:8848",allowCredentials = "true")
public class UserController {
    @ResponseBody
    @GetMapping("register")
    public String register(HttpServletRequest req){
        System.out.println(req.getSession().getId());
        System.out.println(req.getRequestedSessionId());
        return "ok";
    }
}

注意

1. 使用withCredentials来带cookies的方式仅限于根域(顶级域名,如.cn、.com)相同,如果根域不同那么前端依然不会发送cookies
2. ip地址和域名不同,比如localhost和127.0.0.1是不一样的,所以既不能在后端指定允许访问的站点时,对方是域名而用ip,也不能前后端一方使用IP地址一方使用域名,这样会认为根域不同出现第一点的错误

使用JSONP

jsonp是json为解决跨域问题的一种形式,前端发送ajax请求时,使用jsonp来发送数据和接收不同源的站点响应的数据是不会被浏览器拦截的,即使后端没有使用过滤器来设置响应头

总的来说,跨域问题是浏览器为了同源策略导致的,与服务器端无关,跨域的请求来到服务器端服务器依然会执行,但是响应回浏览器的时候,如果浏览器在响应头里面的Access-Control-Allow-Credentials没有找到自己的站点,就会报错;如果需要发送cookies,服务器端使用通配符*来指定允许跨域访问的站点是无效的

异常处理

@ExceptionHandler

SpringMVC提供了异常处理相关的注解@ExceptionHandler,该注解用于修饰方法,注解的value值为异常类的class数组类型,当该Controller发生异常时,会自动跳转到该注解修饰的方法,相当于try-catch然后在catch中执行该方法。如果没有为注解传参数,那么方法参数中的异常列表将会作为方法将处理的异常类型,该注解修饰方法,只对一个Controller起作用

代码示例

@Controller
@RequestMapping("exception")
public class TestException {

    @GetMapping("test1")
    public String test1(){
        User user = new User();
//        user.setId(12);
        System.out.println(user.getId());
        return "test1";
    }

    @ExceptionHandler
    public void handlerError(NullPointerException e){
        System.out.println("error");
    }
}

@ControllerAdvice

@ControllerAdvice注解可以捕获到其他Controller发生的异常,当其他Controller出现异常的时候,不哦她那个Controller的异常处理器无法处理到,但是@ControllerAdvice修饰的Controller下的处理器可以全局处理异常

代码示例

@ControllerAdvice
public class MyControllerAdvice {

    @ExceptionHandler(NullPointerException.class)
    public void test1(){
        System.out.println("error");
    }
}

自定义视图

SpringMVC可以自定义视图解析器,只需要创建一个类继承自AbstractXXXView(XXX为对应类型的视图),实现其内部的build方法作为解析视图的逻辑,然后使用ModelAndView选择数据和视图即可

导出Excel视图代码示例

  1. 先导入apache-poi依赖,用于生成excel
    controller
@Controller
@RequestMapping("view")
public class TestView {

    @GetMapping("test1")
    public ModelAndView test1(){
        User user = new User();
        user.setName("张三");
        User user1 = new User();
        user1.setName("李四");
        List<User> users = new ArrayList<>();
        users.add(user);
        users.add(user1);
        ModelAndView mv = new ModelAndView();
        mv.setView(new ExcelView());
        mv.addObject("users",users);
        return mv;
    }
}

View

public class ExcelView extends AbstractXlsView {
    @Override
    protected void buildExcelDocument(Map<String, Object> model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Sheet sheet = workbook.createSheet("用户信息");//创建表
        Row header = sheet.createRow(0);//创建行
        header.createCell(0).setCellValue("用户名");//创建单元格并添加数据

        List<User> data = (List<User>)model.get("users");
        for (int i=0;i<data.size();i++){
            Row row = sheet.createRow(i+1);
            row.createCell(0).setCellValue(data.get(i).getName());
        }

        response.setHeader("Content-Disposition","attachment;fileName"+ URLEncoder.encode("用户","UTF-8")+".xlsx");
    }
}

事务

事务的xml配置

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" isolation="DEFAULT" propagation="REQUIRED" read-only="true"/>
        </tx:attributes>
    </tx:advice>

name表示添加事务的方法,如get*表示通配get开头的方法名
propagation配置事务的传播机制
isolation配置事务的隔离级别,大部分情况下默认的隔离级别最优
read-only表示事务为只读,即不对数据库的数据进行操作,只读取数据,性能会高一些
rallback-for/no-rallback-for表示对某类异常进行事务处理,详见回滚

传播机制

  1. REQUIRED:默认,支持当前事务,如果当前事务不存在,则创建一个新事务
  2. SUPPORTS:支持当前事务,如果当前事务不存在,则不使用事务
  3. MANDATORY:支持当前事务,如果当前事务不存在,则抛出异常(表示强制必须有事务)
  4. REQUIRES_NEW:创建一个新事务,如果当前存在事务,则将当前事务挂起
  5. NO_SUPPORTED:无事务执行,如果当前事务存在,则将当前事务挂起
  6. NEVER:无事务执行,如果当前存在事务,则抛出异常
  7. NESTED:嵌套事务,如果当前事务存在,那么在嵌套的事务中执行;否则同REQUIRED

传播机制详解

伪代码:

@Transactional
public void ServiceB(){
	@Transactional
	ServiceA();
}

当前事务:这里B方法调用了A方法,当B方法存在事务时,执行到A方法时,A方法也会存在事务,对于A来说,这个事务就是当前已存在的事务

  1. REQUIRED:如果B方法存在事务,则支持事务,如果不存在那么在A方法上会新建一个事务
  2. SUPPORTS:如果B方法存在事务,则支持事务,如果不存在那么不使用事务
  3. MANDATORY:如果B方法存在事务,则支持事务,如果不存在就抛出异常
    1,2,3三种事务传播机制内外层共用一个事务,当内层或外层抛出异常时,事务将回滚
  4. REQUIRES_NEW:创建一个新事务,如果B方法已经存在事务,挂起当前事务(外层事务)。内层事务结束了内层直接提交,不用等外层;内层抛出异常时,如果外层没有捕获那么内层的异常则内外层均回滚,如果捕获了则内层回滚外层不回滚
  5. NESTED:创建一个新事物,如果B方法已存在事务,那么将会嵌套一个子事务。内层事务结束后需要等外层的父事务一起提交,如果内层抛出异常,无论外层是否捕获,内外层都会一起回滚
    4,5两种事务传播机制内外层有两个事务
  6. NO_SUPPORTED:这里当A方法指定传播机制为NO_SUPPORTED时,则表示A方法不执行事务,当B存在事务时,将事务挂起,当A方法执行结束后事务才继续(A方法抛出的异常不会导致事务的回滚)
  7. NEVER:这里A方法执行传播机制为NEVER而B方法存在事务时,就会抛出异常

回滚

Spring整合MyBatis之后,事务的回滚是指捕获到RuntimeException或者Error时,Spring会将底层的各种数据库操作异常包装成DataAccessException(该异常是运行时异常);对于非运行时异常,如IOException,Spring默认不会进行事务回滚,所以有需要的时候就使用rallback-for="IOException"来为指定的异常添加回滚

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值