SpringMVC框架(三)

一、异步请求

1.1 概述

(1)同步请求
当浏览器请求服务器的时候,必须要先等待服务器的响应。在服务器响应之前,用户会一直处于等待状态,而且在浏览器上是看不到任何东西的。但是这样有个问题,如果服务器处理的时间很长,那么对于用户的体验就非常不好。
在这里插入图片描述

(2)异步请求
页面的加载和数据的获取是不同步的。例如:用户在页面上填写数据,然后把数据提交给服务器。如果是使用异步请求方式提交数据,那么在提交数据的过程中,用户无需等待服务器的回应,可以继续执行其他操作。

1.2 ajax异步请求

  • 使用原生的JS发送异步请求的步骤:

第一步:创建XMLHttpRequest对象;
第二步:连接服务器;
第三步:发送请求;
第四步:接收响应数据;

<script>
	//第一步:创建XMLHttpRequest对象;
	var xhr = new XMLHttpRequest();
	//第二步:连接服务器;
	xhr.open('GET', "${pageContext.request.contextPath}/getText.do");
	//第三步:发送请求;
	xhr.send();
	//第四步:接收响应数据;
	xhr.onreadystatechange = function() {
		//readyState:xhr对象的状态,4代表已经完成了HTTP响应的接收
		//status:响应状态,200代表响应成功
		if (xhr.readyState == 4 && xhr.status == 200) {
			alert(xhr.responseText);
		}
	}
</script>

1.3 JQuery发送异步请求

$.post(url, data, fn):发送post请求。
$.get(url, date, fn):发送get请求。
$.getJson(url, data, fn):使用Get请求加载JSON数据。该方法只能够接收服务器返回的JSON格式的数据。

$.getJSON("${pageContext.request.contextPath}/getText.do", //请求URL
	{id:'110',name:'小宝'}, //请求参数
	function(jsonData) { //回调函数
		alert(jsonData.msg);
	}
);

后台实现:

(1)返回JSON格式字符串。

@RequestMapping(value="/getText2.do", produces="application/json;charset=utf-8")
@ResponseBody
public String getText2(String id, String name) throws Exception {
	return "{'msg', '响应成功'}";
}

(2)返回Map集合。

第一步:引入jackson相关的jar包;
在这里插入图片描述
第二步:定义控制器方法,该方法可以返回一个Map集合。

@RequestMapping(value="/getText.do", produces="application/json;charset=utf-8")
@ResponseBody
public Map<String, Object> getText(String id, String name) throws Exception {
	System.out.println("id = " + id + ", name = " + name);
	Map<String, Object> map = new HashMap<String, Object>();
	map.put("msg", "响应成功");
	return map;
}

1.4 异步文件上传

1.4.1 前端页面

如果要实现表单的异步提交,我们可以使用jquery.form插件。

第一步:导入jquery.form插件;
在这里插入图片描述
第二步:定义文件上传表单;

<!-- 文件上传表单 -->
<form id="uploadForm" enctype="multipart/form-data">
	<input type="file" name="pic"/>
	<input type="submit" value="提交"/>
</form>
<!-- 显示上传文件 -->
<div id="imgs"></div>

第三步:获取表单对象,然后调用ajaxForm方法初始化表单;

$("#uploadForm").ajaxForm({
	url: "${pageContext.request.contextPath}/upload.do", // 请求URL
    type: "post", // 请求方式
    dataType: "text", // 响应回来的数据类型
    async: true, // 异步
    success: function(data){ // 请求成功
    	alert(data);
    	var imgUrl = "${pageContext.request.contextPath}" + data;
    	$("<img/>").attr("src", imgUrl).width(200).height(200).appendTo("#imgs");
    },
    error: function(){ // 请求失败
    	alert("数据加载失败!");
    }
});

1.4.2 后台实现

@Controller
public class UploadController {
	
	@RequestMapping(value="/upload.do")
	@ResponseBody
	public String upload(HttpServletRequest request
			, @RequestParam(value="pic") MultipartFile file) throws Exception {
		//获取保存文件的真实路径
		String savePath = request.getServletContext().getRealPath("/uploads");
		//获取上传的文件名
		String fileName = file.getOriginalFilename();
		//创建File对象
		File targetFile = new File(savePath, fileName);
		//保存文件
		file.transferTo(targetFile);
		//返回上传文件的路径
		return "/uploads/" + fileName;
	}

}

文件上传成功后,返回上传文件的URL。

二、SpringMVC表单标签

使用SpringMVC表单标签最大的好处就是它支持数据绑定。

首先,我们需要导入标签库文件。

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

然后,使用SpringMVC标签库中定义了的标签构建表单。

<form:form action="${pageContext.request.contextPath}/regist.do" 
	method="post" modelAttribute="user"><br/>
	用户名:<form:input path="userName" /><br/>&nbsp;码:<form:password path="userPass" /><br/>&nbsp;别:<form:radiobutton path="gender" value="male"/><form:radiobutton path="gender" value="female"/><br/>
	兴趣爱好:<form:checkbox path="favors" value="eat"/><form:checkbox path="favors" value="drink"/><form:checkbox path="favors" value="play"/><br/>
	所在地:<form:select path="city">
		<form:option value="GZ">广州</form:option>
		<form:option value="ZS">中山</form:option>
		<form:option value="ZH">珠海</form:option>
	</form:select><br/>
	自我介绍:<form:textarea path="introduce"/><br/>
	<input type="submit" value="提交"/>
</form:form>

上面form:form标签的commandName属性用于指定绑定到后台JavaBean对象的名字。该JavaBean一定要在request等属性里面有,否则页面会报错的。

除此以外,springmvc为每一个表单标签都提供了对应的标签。例如:

标签名作用
<form:form>定义一个表单
<form:input>定义一个单行的文本输入框
<form:password>定义一个密码输入框
<form:radiobutton>定义一个单选按钮
<form:checkbox>定义一个复选框
<form:select>定义一个列表框
<form:option>定义一个列表框的选项
<form:textarea>定义一个多行的文本框

三、SpringMVC数据校验

3.1 JSR-303概述

JSR是Java Specification Requests的缩写,中文意思是Java规范要求。因为JAVA的功能和版本在不断的更新,JSR就是用来规范这些功能和接口。
在这里插入图片描述
制定JSR是由在JAVA业界有重要贡献的个人、组织或者公司,例如IBM,Google, Apache等等。

Bean Validation(JSR-303)是一个Java的数据验证规范,2009 年 12月伴随着Java EE 6一起发布。从SpringMVC 3开始提供了JSR-303验证框架的支持,JSR 303 的发布使得在数据自动绑定和验证变得简单。JSR-303通过注解方式对Java Bean 中字段的值进行验证。具体可以参考它的官方网站:http://beanvalication.org。

目前Bean Validation最新版本是2.0(JSR-380),它除了支持通过注解方式为对象模型添加约束之外,还支持自定义校验规则、分组验证等功能。

3.2 JSR303规范相关的注解

在这里插入图片描述

3.3 Hibernate Validator

Hibernate Validator 提供了JSR -303规范中所有内置 constraint 的实现,除此以外,它还在JSR-303的基础上附加了一些额外的constrainst。
在这里插入图片描述

3.4 数据校验

第一步:下载Hibernate Validator压缩包(http://hibernate.org/validator)
在这里插入图片描述
下载完成后解压缩,然后把hibernate-validator-6.0.17.Final.jar文件拷贝到项目中。另外,还要把dist/lib/required文件夹下的所有依赖的jar包也要拷贝到项目中。
在这里插入图片描述

第二步:对需要添加约束的JavaBean属性指定约束规范;
在这里插入图片描述
第三步:在控制器方法参数添加@Valid或@Validated注解;
在这里插入图片描述
第四步:在JSP页面中导入springmvc标签库,并且使用form:errors标签显示错误信息。

<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
...
<form:form commandName="user">
	<form:errors path="*" classStyle="color:red"></form:errors>
	<form:errors path="age" cssStyle="color:red"></form:errors>
</form:form>

上面form:form标签中的commandName属性用于指定需要进行验证的JavaBean。form:errros标签中的path属性用于指定对user对象的哪个属性进行数据校验。星号*代表所有属性。

四、SSM整合

4.1 准备环境

第一步:下载压缩包,解压缩后拷贝jar包到项目中;

  • spring
  • mybatis
  • mybatis-spring
  • aopalliance
  • aspectjweaver
  • common-logging
  • jackson-annotations
  • jackson-core
  • jackson-databind
  • 数据库驱动包

下载地址:https://pan.baidu.com/s/1q75ST52jThA74SdbKRlA-Q

第二步:创建数据库表;

create table user(
	id int primary key auto_increment, 
	name varchar(255) not null default '',
	age int not nul default 0
);

第三步:创建实体;

package ssmtest.beans;

public class User {
	private Integer id;
	private String name;
	private Integer age;

	// 省略了setters和getters方法...
}

第四步:定义映射接口;

@Repository
public interface UserMapper {
	
}

第五步:新建业务接口和实现类,并且在业务类中注入映射接口;

业务接口:

package ssmtest.service;

public interface IUserService {

}

实现类:

package ssmtest.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import ssmtest.mapper.UserMapper;
import ssmtest.service.IUserService;

@Service
public class UserServiceImpl implements IUserService {
	@Autowired
	private UserMapper userMapper;
	
}

第六步:新建一个控制器类,并且把业务类注入到该控制器中;

package ssmtest.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import ssmtest.service.IUserService;

@Controller
public class UserController {
	@Autowired
	private IUserService userService;
	
}

第七步:在src目录下创建spring配置文件,名称为applicationContext.xml,并启用注解和包扫描功能;

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:mvc="http://www.springframework.org/schema/mvc"
	   xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
      					 http://www.springframework.org/schema/beans/spring-beans.xsd
      					 http://www.springframework.org/schema/mvc
      					 http://www.springframework.org/schema/mvc/spring-mvc.xsd
      					 http://www.springframework.org/schema/context
      					 http://www.springframework.org/schema/context/spring-context.xsd">		 
      <!-- 启动注解功能 -->
      <mvc:annotation-driven/>
      <!-- 启用报扫描功能 -->
      <context:component-scan base-package="ssmtest" />  
</beans>

第八步:在web.xml文件中配置springmvc核心控制器和spring容器;

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	id="WebApp_ID" version="3.1">

	<!-- 指定Spring配置文件路径 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>

	<!-- 加载Spring容器 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- springmvc核心控制器 -->
	<!-- 配置Spring的核心控制器 -->
	<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>
	</servlet>
	<servlet-mapping>
		<servlet-name>SpringMVC</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
	
</web-app>

上面配置指定springmvc配置文件的路径与spring配置文件路径相同。

4.2 整合SSM

第一步:配置数据源;

<bean id="dataSource"
	class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
	<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
	<property name="username" value="root"></property>
	<property name="password" value="root"></property>
</bean>

第二步:配置SqlSessionFactory;

<bean name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
</bean>

第三步:配置Mapper扫描器;

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
	<property name="basePackage" value="ssmtest.mapper"></property>
</bean>

第四步:配置事务管理器;

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

<!-- 开启事务注解功能 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

上面开启事务注解功能的时候使用了tx命名空间下的annotation-driven标签,所以需要引入该命名空间。
在这里插入图片描述

第五步:配置视图解析器;

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

4.3 测试

第一步:修改Mapper接口,定义一个addUser方法,然后在注解上指定添加用户的sql命令;

@Insert("insert into user(name, age) values(#{name}, #{age})")
void addUser(User user);

第二步:在Service接口中提供addUser方法,然后在Service实现类中实现该方法;

// 定义接口方法
void addUser(User user);

// 在实现类中实现该方法
@Override
public void addUser(User user) {
	userMapper.addUser(user);
}

第三步:在UserController中定义一个方法,该方法调用Service的addUser方法,实现添加用户功能。

@RequestMapping(path="/saveUser", produces={"text/html;charset=utf-8"})
@ResponseBody
public String saveUser() {
	System.out.println("saveUser...");
	User user = new User();
	user.setName("jacky");
	user.setAge(18);
	userService.addUser(user);
	return "添加成功";
}

第四步:启动服务器,然后在浏览器输入地址localhost:8080/ssmtest/saveUser。如果运行后控制台没有出现错误提示,而且查看数据库表中也有新增用户的记录,代表整合成功。
在这里插入图片描述

五、实现登录认证

这里结合之前学习过的aop技术来实现登录认证功能。实现思路如下:
1)定义一个注解,注解名字为LoginFilter;
2)在需要拦截的方法上使用该注解;
3)定义一个切面类,然后在切面类中定义一个通知方法,并指定@Around类型的通知,该通知指定对使用了@LoginFilter注解的方法进行切入;
4)实现该方法。首先从session中获取登录用户,如果登录用户为空,代表用户还没登录,提示用户。如果用户不为空,则调用目标方法,并返回该方法的返回值;
5)在spring配置文件中启用aop功能;

下面详解介绍具体如何实现登录认证功能。

5.1 定义@LoginFilter

package ssmtest.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface LoginFilter {
	String name() default "";
}

上面代码定义了一个名为LoginFilter的注解,该注解可以在犯法上使用,也可以在类上使用。

5.2 使用@LoginFilter注解

假如需要对UserController的saveUser方法进行登录认证,所以在该方法上使用@LoginFilter注解。

@LoginFilter
@RequestMapping(path="/saveUser", produces={"text/html;charset=utf-8"})
@ResponseBody
public String saveUser() {
	System.out.println("saveUser...");
	User user = new User();
	user.setName("jacky");
	user.setAge(18);
	userService.addUser(user);
	return "添加成功";
}

5.3 定义切面类

该切面类相当于Servlet的过滤器,当执行@LoginFilter标注的方法时候,会先执行该切面类中定义的方法。

package ssmtest.aspect;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;


@Component
@Aspect
public class LoginAspect {
	@Autowired  
	private HttpServletRequest request; 

	// 在执行@LoginFilter注解的控制器方法的时候,该方法都会被执行
	// 该方法用于判断用户是否已经登录,只有用户已经登录,才执行目标方法
	@Around("@annotation(ssmtest.annotation.LoginFilter)")
	public Object checkUserLoginStatus(ProceedingJoinPoint pjp) throws Throwable {
		HttpSession session = request.getSession();
		Object o = session.getAttribute("loginUser");
		// 判断session中是否有登录用户信息
		if (o == null) {
			return "请先登录";
		} else {
			// 返回目标方法的返回值
			return pjp.proceed(pjp.getArgs());
		}
	}
}

@annotation(注解类名)表示对指定注解类型所标注的方法方法进行增强处理。

5.4 启用aop功能

修改spring配置文件,并加入以下配置内容:

<aop:aspectj-autoproxy/>

上面使用了aop命名空间下的aspectj-autoproxy标签,所以需要引入aop命名空间。
在这里插入图片描述

5.5 测试

第一步:新建一个控制器,并提供登录方法。

package ssmtest.controller;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SysController {
	
	@RequestMapping(path="/login", produces={"text/html;charset=utf-8"})
	@ResponseBody
	public String login(HttpSession session) {
		session.setAttribute("loginUser", "jacky");
		return "登录成功";
	}
	
}

第二步:启动服务器,然后按照下面步骤进行测试。

首先,在浏览器中先访问localhost:8080/ssmtest/saveUser,界面显示如下:
在这里插入图片描述
然后,访问localhost:8080/ssmtest/login,默认用户登录的行为:
在这里插入图片描述
最后,重新访问localhost:8080/ssmtest/saveUser,这时候显示“添加成功”。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值