六.数据处理
6.4乱码问题
测试步骤
1.我们首先在首页页面写一个form表单 用来提交数据(Get方式提交一般不会产生乱码)
<form action="/filter/t1" method="Post">
<input type="text" name="name"/>
<input type="text" name="age"/>
<input type="submit" value="提交">
</form>
2.编写Controller控制器 处理前台的数据
@PostMapping("/filter/t1")
public String test1(String name, int age, Model model) {
model.addAttribute("name", name);
model.addAttribute("age", age);
System.out.println(name);
System.out.println(age);
return "hello01";
}
3.输入中文 发现乱码
不得不说,乱码问题是在我们开发中十分常见的问题,也是我们特别头大的问题!
以前乱码问题通过过滤器解决 , 而SpringMVC给我们提供了一个过滤器 , 可以在web.xml中配置 . 修改了xml文件需要重启服务器
处理方法:
方法一:找到tomcat包config下的server.xml 添加其编码格式 (F:\DevInstall\apache-tomcat-9.0.31\conf)
<Connector port="8888" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"/>
如果没有解决 就尝试下方法二
方法二:在web.xml中配置了 DispatchServlet过滤器
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意:<url-pattern>/*</url-pattern>
的书写内容
“/”: 一般表示过滤不到后缀名的文件 不包括.jsp文件
“/*”: 一般表示带后缀名的文件,包括.jsp文件
到这里一般乱码问题就会迎刃而解,如果还出现乱码情况 就尝试方法三
方法三:自定义过滤器
在filter包下创建一个EncodingFilter 类实现过滤操作
package com.zz.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
* @Author 张哲
* @Date 2020/8/2 7:58
*/
public class EncodingFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
//处理response的字符编码
HttpServletResponse myResponse = (HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
filterChain.doFilter(myrequest, response);
}
public void destroy() {
}
}
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}
//取一个值
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}
//取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
注意:创建该过滤器后要在web.xml文件中注册该过滤器,否则不生效
<!--在filter中自定义过滤器-->
<filter>
<filter-name>filter</filter-name>
<filter-class>com.zz.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这个是在网上找的一些大神写的,一般情况下,SpringMVC默认的乱码处理就已经能够很好的解决了!
乱码问题,需要平时多注意,在尽可能能设置编码的地方,都设置为统一编码 UTF-8!
八.json
8.1、什么是JSON
- JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别广泛。
- 采用完全独立于编程语言的文本格式来存储和表示数据。
- 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
- 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
- 在 JavaScript 语言中,一切都是对象。因此,任何JavaScript 支持的类型都可以通过 JSON
来表示,例如字符串、数字、对象、数组等。看看他的要求和语法格式: - 对象表示为键值对,数据由逗号分隔
- 花括号保存对象
- 方括号保存数组
很多人搞不清楚 JSON 和 JavaScript 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:
JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
//定义一个javascript对象
var user={
name:"张哲",
age:21,
city:"河南"
};
console.log(user);
要实现从JavaScript 对象转换为JSON字符串,使用 JSON.stringify() 方法:
// 实现从javascript 对象转换成json对象
var json = JSON.stringify(user);
console.log(json);
//结果:{"name":"张哲","age":21,"city":"河南"}
要实现从JSON字符串转换为JavaScript 对象,使用 JSON.parse() 方法:
//将json对象转换为js对象
var parse = JSON.parse(json);
console.log(parse);
//结果:{name:"张哲",age:21,city:"河南"}
代码测试
1、新建一个module ,springmvc-05-json , 添加web的支持
2、在web目录下新建一个 json-1.html , 编写测试内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
//定义一个javascript对象
var user={
name:"张哲",
age:21,
city:"河南"
};
console.log(user);
// 实现从javascript 对象转换成json对象
var json = JSON.stringify(user);
console.log(json);
//将json对象转换为js对象
var parse = JSON.parse(json);
console.log(parse);
</script>
</head>
<body>
</body>
</html>
3.在浏览器控制台 查看输出格式
8.2Controller返回JSON数据
- Jackson应该是目前比较好的json解析工具了
- 当然工具不止这一个,比如还有阿里巴巴的 fastjson 等等。
- 我们这里使用Jackson,使用它需要导入它的jar包;
<!--json数据解析-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
配置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:springmvc-servlet.xml</param-value>
</init-param>
<!--启动顺序 数字越小 启动越早-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--所有请求都会被springmvc拦截 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--配置DispatcherServlet 中文乱码过滤器-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
springmvc-servlet.xml
<context:component-scan base-package="com.zz.controller"/>
<!--过滤静态资源-->
<mvc:default-servlet-handler/>
<!--json乱码配置-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--视图解析器:DispatcherServlet给他的ModelAndView-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
web.xml
<!-- 可以将 GET 和 POST 请求通过过滤器转化成 DELETE 和 PUT 请求-->
<!-- 配置HiddenHttpMethodFilter过滤器 -->
<filter>
<filter-name>hiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>hiddenHttpMethodFilter</filter-name>
<!--拦截所有请求-->
<url-pattern>/*</url-pattern>
</filter-mapping>
由于浏览器表单无法发送 DELETE 和 PUT 请求,所以为了让 HiddenHttpMethodFilter 识别请求的方法,需要在表单中添加一个隐藏域,名字为 _method 值为 DELETE 或 POST 或PUT,修改后 index.jsp 页面代码如下:
<!-- 新建id为1的user -->
<form action="user" method="post">
<input type="hidden" name="_method" value="DELETE"/>
<input type="submit" value="Test Rest DELETE"/>
</form>
Controller层
@RequestMapping(value="/user/{id}", method=RequestMethod.DELETE)
public String destroy(@PathVariable("id") Integer id) {
System.out.println("删除id为:" + id + "的user");
return "success";
在pojo包下面编写一个User的实体类,然后去编写我们的测试Controller;
package com.zz.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @Author 张哲
* @Date 2020/8/2 9:51
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private int age;
private String sex;
}
在controller包下面编写UserController类
这里我们需要两个新东西,一个是@ResponseBody,一个是ObjectMapper对象,我们看下具体的用法
@Controller
//整合了@Controller+@ResponseBody 作用的效果 定义在类上
/*@RestController*/
public class UserJson {
//原生态解决json中文乱码问题
//@RequestMapping(value = "/json/t1", produces = "application/json;charset=utf-8")
@RequestMapping("/json/t1")
//他不会走视图解析器 会直接返回一个字符串(能实现前后端分离)
@ResponseBody
public String json1() throws JsonProcessingException {
//创建一个jackson的对象映射器,用来解析数据
ObjectMapper mapper = new ObjectMapper();
//创建一个对象
User user = new User("张哲", 21, "男");
//讲对象转换成json格式
String value = mapper.writeValueAsString(user);
//由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
return value;
}
}
代码中详细解释了@ResponseBody、@RestController的用法和区别
还有json数据解析乱码问题 解决方式
1.@RequestMappin请求方式这样写
@RequestMapping(value = "/json/t1", produces = "application/json;charset=utf-8")
2.在springmvc-servlet.xml文件中配置如下
<!--json乱码配置-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
8.3 测试集合输出
@RequestMapping("/json/t2")
@ResponseBody
public String json2() throws JsonProcessingException {
//测试集合转换成json格式数据
List<User> list = new ArrayList<User>();
ObjectMapper mapper = new ObjectMapper();
User user1 = new User("张哲1", 21, "男");
User user2 = new User("张哲2", 21, "男");
User user3 = new User("张哲3", 21, "男");
User user4 = new User("张哲4", 21, "男");
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
String value = mapper.writeValueAsString(list);
return value;
}
运行结果:
注意:一般在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !我们在前后端分离开发中,一般都使用 @RestController ,十分便捷!
8.4输出时间对象
@RequestMapping("/json/t3")
@ResponseBody
public String json3() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Date date = new Date();
String value = mapper.writeValueAsString(date);
return value;
}
运行结果:
- 默认日期格式会变成一个数字,是1970年1月1日到当前日期的毫秒数!
- Jackson 默认是会把时间转成timestamps形
解决方案:取消timestamps形式 , 自定义时间格式
@RequestMapping("/json/t4")
@ResponseBody
public String json4() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//不适用时间戳格式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
//使用时间格式
mapper.setDateFormat(simpleDateFormat);
Date date = new Date();
String value = mapper.writeValueAsString(date);
return value;
}
成功输出
8.5 抽取为工具类
如果要经常使用的话,这样是比较麻烦的,我们可以将这些代码封装到一个工具类中;
在utils包下创建一个JsonUtils工具类
/**
- @Author 张哲
- @Date 2020/8/2 12:01
*/
public class JsonUtils {
public static String getJson(Object object) {
//转换为指定的时间格式
return getJson(object, "yyyy-MM-dd HH-mm-ss");
}
public static String getJson(Object object, String dataFormat) {
ObjectMapper mapper = new ObjectMapper();
//不适用时间戳格式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dataFormat);
//使用时间格式
mapper.setDateFormat(simpleDateFormat);
try {
String value = mapper.writeValueAsString(object);
return value;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
Controller调用
@RequestMapping("/json/t1")
@ResponseBody
public String json1() throws JsonProcessingException {
//创建一个对象
User user = new User("张哲", 21, "男");
//调用工具类中的方法
String json = JsonUtils.getJson(user);
return json;
}
@RequestMapping("/json/t4")
@ResponseBody
public String json4() {
Date date = new Date();
String json = JsonUtils.getJson(date);
return json;
}
8.6 FastJson
fastjson.jar是阿里开发的一款专门用于Java开发的包,可以方便的实现json对象与JavaBean对象的转 换,实现JavaBean对象与json字符串的转换,实现json对象与json字符串的转换。实现json的转换方法 很多,最后的实现结果都是一样的。
fastjson 的 pom依赖
<!--fastjson数据解析-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
fastjson 三个主要的类:
- 【JSONObject 代表 json 对象 】
- 【JSONArray 代表 json 对象数组】
- 【JSON 代表 JSONObject和JSONArray的转化】
测试实现:
@RequestMapping(value = "/fastjson")
@ResponseBody
public void fastjso(){
//创建一个对象
User user1 = new User("秦疆1号", 3, "男");
User user2 = new User("秦疆2号", 3, "男");
User user3 = new User("秦疆3号", 3, "男");
User user4 = new User("秦疆4号", 3, "男");
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
//java对象转json对象
String str2 = JSON.toJSONString(user1);
//{"age":3,"name":"秦疆1号","sex":"男"}
System.out.println(str2);
//json对象转java对象
User jp_user1=JSON.parseObject(str2,User.class);
//User(name=秦疆1号, age=3, sex=男)
System.out.println(jp_user1);
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
//秦疆2号
System.out.println(jsonObject1.getString("name"));
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
//User(name=秦疆2号, age=3, sex=男)
System.out.println(to_java_user);
}
这种工具类,我们只需要掌握使用就好了,在使用的时候在根据具体的业务去找对应的实现。和以前的 commons-io那种工具包一样,拿来用就好了!
九、ajax
- AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
- AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
- Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术。
- 在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。Google Suggest能够自动帮你完成搜索单词。
- Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表。
- 就和国内百度的搜索框一样!
- 传统的网页(即不用ajax技术的网页),想要更新内容或者提交一个表单,都需要重新加载整个网页。
- 使用ajax技术的网页,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新。
- 使用Ajax,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的Web用户界面。
9.1、伪造ajax操作
1、创建一个test.html静态页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>iframe</title>
</head>
<script>
function go() {
var url=document.getElementById("url").value;
document.getElementById("ifream1").src=url;
}
</script>
<body>
<div>
<p>
<input type="text" id="url" value="https://www.baidu.com/">
<input type="button" value="提交" onclick="go()">
</p>
</div>
<div>
<iframe id="ifream1" style="width: 95%;height: 800px">
</iframe>
</div>
</body>
</html>
当点击提交后 请求百度的地址 并显示页面到指定的div中
效果:
9.2、jQuery.ajax
纯JS原生实现Ajax我们不去讲解这里,直接使用jquery提供的,方便学习和使用,避免重复造轮子,有兴趣的同学可以去了解下JS原生XMLHttpRequest !
Ajax的核心是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据。
jQuery 提供多个与 AJAX 有关的方法。
通过 jQuery AJAX 方法,您能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON – 同时您能够把这些外部数据直接载入网页的被选元素中。
jQuery 不是生产者,而是大自然搬运工。
jQuery Ajax本质就是 XMLHttpRequest,对他进行了封装,方便调用!
jQuery.ajax(...)
部分参数:
url:请求地址
type:请求方式,GET、POST(1.9.0之后用method)
headers:请求头
data:要发送的数据
contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否异步
timeout:设置请求超时时间(毫秒)
beforeSend:发送请求前执行的函数(全局)
complete:完成之后执行的回调函数(全局)
success:成功之后执行的回调函数(全局)
error:失败之后执行的回调函数(全局)
accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
dataType:将服务器端返回的数据转换成指定类型
"xml": 将服务器端返回的内容转换成xml格式
"text": 将服务器端返回的内容转换成普通文本格式
"html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
"script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
"json": 将服务器端返回的内容转换成相应的JavaScript对象
"jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数
1、jQuery官网下载jquery-3.4.1.js
作为原生态的js源码
2、把该文件放到web下的static文件夹下
3、编写html页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
<script src="${pageContext.request.contextPath}/static/jquery-3.4.1.js"></script>
<script>
function a() {
$.post({
url:"${pageContext.request.contextPath}/a1",
data:{"name":$("#username").val()},
success: function (data,status) {
//控制台Console显示请求的信息
/*console.log("data-->"+data);
console.log("status-->"+status);*/
alert(data);
}
})
}
</script>
</head>
<body>
<%--ajax当失去焦点的时候,向服务器发送一个请求--%>
<input type="text" id="username" onblur="a()">
</body>
</html>
4、Controller
@RestController
public class ajaxController {
@RequestMapping("/a1")
public void ajax(String name, HttpServletResponse response) throws IOException {
if ("admin".equals(name)){
response.getWriter().print("true");
}else {
response.getWriter().print("false");
}
}
}
true
false
9.3、ajax操作实体类
1、创建一个实体类user
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private String sex;
private int age;
}
2、Controller方法
@RequestMapping("/a2")
public List<User> ajax01() {
ArrayList<User> list = new ArrayList<User>();
list.add(new User("小明", "男", 15));
list.add(new User("小刘", "女", 21));
list.add(new User("小张", "男", 16));
return list;
}
3、在web下面创建ajax.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="${pageContext.request.contextPath}/static/jquery-3.4.1.js"></script>
<script>
$(function () {
$("#btn").click(function () {
/*
$.post(url,parm(可以省略),success)
*/
$.post("${pageContext.request.contextPath}/a2", function (data) {
var html = "";
for (let i = 0; i < data.length; i++) {
html += "<tr>" +
"<td>" + data[i].name + "</td>" +
"<td>" + data[i].sex+ "</td>" +
"<td>" + data[i].age+ "</td>" +
"</tr>"
}
$("#content").html(html);
})
})
});
</script>
</head>
<body>
<input type="button" value="加载数据" id="btn" onclick="click">
<table>
<tr>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
</tr>
<tbody id="content">
</tbody>
</table>
</body>
</html>
当点击加载数据按钮时,后台数据没经过服务器,将后台信息 提交到前台页面 运用了ajax技术
运行结果:
9.4、ajax实现用户登录提示
用于用户名 密码的验证 给出用户提示信息,使用户体验感更好
Controller
@RequestMapping("/a3")
public String login(String name, String pwd) {
String msg = "";
if (name != null) {
if ("zhang".equals(name)) {
msg = "OK";
} else {
msg = "用户名错误";
}
}
if (pwd != null) {
if ("123456".equals(pwd)) {
msg = "OK";
} else {
msg = "密码错误";
}
}
return msg;
}
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<script src="${pageContext.request.contextPath}/static/jquery-3.4.1.js"></script>
<script>
function a1() {
$.post({
url: "${pageContext.request.contextPath}/a3",
//key-value值 key为用户后台传的参数 value:为用户文本框的id 来获取用户输入的值
data: {"name": $("#name").val()},
// 通过匹配渠道后台 返回的值 保存到data数据中
success: function (data) {
if (data.toString()==="OK"){
$("#userinfo").css("color","green");
}else {
$("#userinfo").css("color","red");
}
$("#userinfo").html(data);
}
})
}
function a2() {
$.post({
url: "${pageContext.request.contextPath}/a3",
data: {"pwd": $("#pwd").val()},
success: function (data) {
if (data.toString()==="OK"){
$("#pwdinfo").css("color","green");
}else {
$("#pwdinfo").css("color","red");
}
$("#pwdinfo").html(data);
}
})
}
</script>
<body>
<p>
用户名:<input type="text" id="name" onblur="a1()"/>
<span id="userinfo"></span>
</p>
<p>
密码:<input type="text" id="pwd" onblur="a2()"/>
<span id="pwdinfo"></span>
</p>
</body>
</html>
运行结果:
十、拦截器
10.1、登录功能添加拦截器
1、完善登录页面,在该网站没有登录用户之前,为了安全性不允许用户登录其他页面,其中就运用了拦截器功能,当session中没有对象时,不能进行其他页面的跳转,当存入session对象时,才能进行其他页面的访问,并且通过AJAX实现了判断用户名 密码是否正确的功能
2、首先定义一个起始页面index.jsp
通过点击跳转到 用户登录的界面
<a href="${pageContext.request.contextPath}/user/tologin">点击登录</a><br>
<a href="${pageContext.request.contextPath}/user/tomain">首页</a>
3、当点击“点击登录”链接时通过tologin()
方法跳转到login.jsp
登录界面,该页面定义了一个用户登录的form表单,当提交表单时,通过login()
方法跳转到main.jsp
页面,说明登录成功,并运用了ajax功能判断用户名密码 是否登录正确(这里没有做数据库的连接 所有没有复杂的实现),最后在首页有一个退出功能,通过移除session中的对象,最后跳转到登录页面。
(1)在spingmvc-servlet.xml中注册拦截器
<!--拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--拦截哪个请求-->
<mvc:mapping path="/user/**"/>
<!--让谁拦截-->
<bean class="com.zz.config.LoginInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<!--拦截哪个请求-->
<mvc:mapping path="/**"/>
<!--让谁拦截-->
<bean class="com.zz.config.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
(2)在config文件夹下面创建LoginInterceptor.java
public class LoginInterceptor implements HandlerInterceptor {
//true: 放行 执行下一个拦截器
//false: 被拦截器拦截 不能执行下一步
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
//request.getRequestURI() 返回除去host(域名或者ip)部分的路径
//当进入登录页面时放行
if (request.getRequestURI().contains("toLogin")) {
return true;
}
//当提交登录表单的数据时放行
if (request.getRequestURI().contains("login")) {
return true;
}
//当点击退出时,放行
if (request.getRequestURI().contains("logout")) {
return true;
}
//当session中不为空时 说明已经登录 放行
if (session.getAttribute("users") != null) {
return true;
}
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
(3)创建LoginController.java
@Controller
@RequestMapping("/user")
public class LoginController {
//当点击登录链接时 跳转到登录页面
@RequestMapping("/toLogin")
public String tologin() {
//进入登录页面
return "login";
}
@RequestMapping("/logout")
public String logout(HttpSession session) {
//注销用户 退出到首页
if (session != null) {
//清除session
session.removeAttribute("users");
}
//return "forward:/index.jsp";
return "redirect:/index.jsp";
}
@RequestMapping("/login")
public String login(String name, String pwd, HttpSession session, Model model) {
session.setAttribute("users", name);
model.addAttribute("user", name);
return "main";
}
@RequestMapping("/tomain")
public String main() {
return "main";
}
}
(4)、VerifyController.java
该类中方法的返回值不需要视图解析器的解析,直接返回需要的值,做登录信息的校验
@RestController
public class VerifyController {
@RequestMapping("/verify")
@ResponseBody
//进行用户名、密码的校验
public String verify(String name, String pwd) {
String msg = "";
if (name != null) {
if ("zhang".equals(name)) {
msg = "ok";
} else {
msg = "用户名错误";
}
}
if (pwd != null) {
if ("123456".equals(pwd)) {
msg = "ok";
} else {
msg = "密码错误";
}
}
return msg;
}
}
(5)、当用户登录成功后跳转到该main.jsp
页面
<body>
<h2>首页</h2>
<p style="font-weight: bold">${user}</p>
<a href="${pageContext.request.contextPath}/user/logout" style="color: red">退出</a>
</body>
(6)、login.jsp
页面做用户的登录以及用户信息的检验
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script src="${pageContext.request.contextPath}/static/jquery-3.4.1.js"></script>
<script>
function a1() {
$.post({
url: "${pageContext.request.contextPath}/verify",
data: {"name": $("#userName").val()},
success: function (data) {
if (data.toString() === "ok") {
$("#nameInfo").css("color", "green");
} else {
$("#nameInfo").css("color", "red");
}
$("#nameInfo").html(data);
}
})
}
function a2() {
$.post({
url: "${pageContext.request.contextPath}/verify",
data: {"pwd": $("#userPassword").val()},
success: function (data) {
if (data.toString() === "ok") {
$("#passwordInfo").css("color", "green");
} else {
$("#passwordInfo").css("color", "red");
}
$("#passwordInfo").html(data);
}
})
}
</script>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/login" method="post">
<p>
用户名:<input type="text" name="name" id="userName" onblur="a1()">
<span id="nameInfo"></span>
</p>
<p>
密码:<input type="text" name="pwd" id="userPassword" onblur="a2()">
<span id="passwordInfo"></span>
</p>
<input type="submit" value="登录">
</form>
</body>
</html>
十一、文件上传和下载
文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver。
前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;
对表单中的 enctype 属性做个详细的说明:
- application/x-www=form-urlencoded:默认方式,只处理表单域中的 value
属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。 - multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。
- text/plain:除了把空格转换为 “+” 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。
一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。
- Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。
- 而Spring MVC则提供了更简单的封装。
- Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。
- Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:
- CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons
FileUpload的组件。
1、导入maven依赖
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
2、在mvc中配置文件上传的bean
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件大小上限,单位为字节(10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
3、编写Controller
/*
* 采用file.Transto 来保存上传的文件
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
//上传文件地址
System.out.println("上传文件保存地址:"+realPath);
//通过CommonsMultipartFile的方法直接写文件(注意这个时候)
file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
return "redirect:/index.jsp";
}
index.jsp
<form action="${pageContext.request.contextPath}/upload2" enctype="multipart/form-data" method="post">
<input type="file" name="file"/><br>
<input type="submit" value="upload">
</form>
4、文件下载
Controller
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "1.png";
//1、设置response 响应头
response.reset(); //设置页面不缓存,清空buffer
response.setCharacterEncoding("UTF-8"); //字符编码
response.setContentType("multipart/form-data"); //二进制传输数据
//设置响应头
response.setHeader("Content-Disposition",
"attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName);
//2、 读取文件--输入流
InputStream input=new FileInputStream(file);
//3、 写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、执行 写出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
请求下载链接(从该路径下面获取下载资源:E:\IdeaSpringBoot\KSSIdeaCode\SpringMVC\out\artifacts\springmvc_08_file_war_exploded\upload
)
<h3>从upload文件夹下面下载</h3>
<a href="${pageContext.request.contextPath}/download">文件下载</a>