12-web项目其他设置
1、常见乱码及其解决
/**
乱码问题,就是传递的数据的编码与数据所呈现到某个地方的后怎么解码后的结果问题。
要解决该问题,要么改变接收数据那头的解码方式,要么就是改变发送数据那头的编码方式。
当然,比如浏览器,默认的字符编码方式是UTF-8,无论是发送数据还是接收数据,其编码解码方式都是UTF-8.
**/
1、乱码出现的位置
*数据传递过程中的乱码
*数据展示过程中的乱码
*数据存储过程中的乱码
//存储过程中出现乱码
即在数据最终保存在数据库表中的时候,数据出现乱码,有以下两种情况:
第一种:
保存之前就是乱码数据,保存之后还是乱码
第二种:
保存之前不是乱码但是该数据是以GBK编码的
由于数据库本身是不支持简体中文GBK编码的数据,就是说数据无法
GBK解码,保存后就出现乱码
//数据展示过程中的乱码
最终显示到网页的数据出现乱码
解决方式:
首先你要知道浏览器呈现的内容是以什么编码和解码方式进行的,
大多数情况浏览器是使用的字符编码方式是UTF-8,所以在Servlet对
象中将数据输出到浏览器显示时要将传递的数据的字符编码方式设置为UTF-8。
使用下面方法:
//设置响应内容以及字符编码方式(这是执行java程序后,Java程序负责向浏览器响应的内容出现中文乱码):
response.setContentType("text/html;charset=UTF-8")
//当没有经过Java程序,而是将html页面的内容响应到浏览器用以下方法设置页面内容的编码方式:
<meta charset="UTF-8">
或
<meta content="text/html;charset=UTF-8">
//数据传递过程中的乱码
当我们发送请求时,有时需要将表单的数据以GET或者POST方式发送给服务器,服务器接收的数据是乱码。
例如:
我们在浏览器一个页面上的name为dname中输入大家好,点击提交,
浏览器将“dname=市场部”这条数据传给服务器,但是我们用HttpWatch监测请求后,
从请求协议中看到浏览器是将“dname=%E5%B8%82%E5%9C%BA%E9%83%A8”传给服务器的
%E5%B8%82%E5%9C%BA%E9%83%A8是“市场部”的ISO-8859-1的编码方式
这是一种国际标准码,不支持中文编码,兼容ASCII码,又称latin1编码。
无论哪个国家,其浏览器将数据发送给服务器都用ISO-8859-1的编码方式发送。
虽然传送中文字符串数据看起来像是乱码,但是服务器接收后用ISO-8859-1解码后,
再用UTF-8编码还是能得到原来的中文字符串的。
当我们发送数据给web服务器后,服务器不知道这些数据都是什么类型的(中文、日文...)
所以服务器接收到的数据是乱码
//解决数据传递过程中的乱码:
我们系统是中文的,我们需要将中文乱码解决
第一种:万能式,可以解决POST请求和GET请求发送数据的乱码问题
因为我们程序员是知道发送到服务器中的数据有中文的,
就将服务器中接收的数据采用ISO-8859-1解码,回归原始
状态(最原始的二进制)。然后用一种支持简体中文的编码方式重新组装
//在Java程序中获取dname
String dname = request.getParameter("dname");
//解码
byte[] bytes = dname.getByte("ISO-8859-1");
//再用支持中文的编码方式编码组装成字符串,要与浏览器中的字符编码方式一致
dname = new String(bytes,"UTF-8");
System.out.println(dname);
第二种:在Java程序中调用request对象的setCharacterEcoding()方法,该方法只解决POST
//意思是告诉Tomcat服务器,请求体中是数据用UTF-8编码的
//(或者说是将服务器当前请求的的解码方式设置为UTF-8)。
需要注意的是要先设置解码方式,再获取数据
request.setCharacterEcoding("UTF-8");
String dname = request.getParameter("dname");
System.out.println(dname);
第三种:转门解决GET请求的乱码问题,即只对请求行编码
修改Tomcat文件中的config目录下的server.xml文件
CATALINA_HOME/config/server.xml
F:\Git_Repositories\J2EE-servelet\tools\tomcat9\apache-tomcat-9.0.41\conf\server.xml
F:\Git_Repositories\J2EE-servelet\tools\tomcat9\apache-tomcat-9.0.41=CATALINA_HOME
找到Connector标签,如下:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
//添加 URIEncoding="UTF-8"
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"/>
该标签中我们还可修改服务器端口号port为80
还可以修改哪些属性,可以到帮助文档中看,如下:
帮助文档位置: CATALINA_HOME/config/http.html
port 端口
maxThreads 最多支持的线程数量
URIEncoding 设置请求行上的编码方式,解决GET请求乱码。
2、Servlet的线程安全问题
2.1 程序出现线程安全问题的情况
满足下列条件:
--多线程并发
--有共享的数据
--共享的数据有修改的情况
2.2 在JVM中可能存在线程安全的数据
--所有线程是共享一个堆的,所以:
* 由于堆内存中存储了new出来的对象,该对象中有"实例变量",所以"实例变量"的内存多线程共享。
当"实例变量"被共同访问,且涉及到修改操作时存在线程安全问题
--所有线程共享一个方法区
* 方法区中的静态变量被多线程共享,涉及到修改操作时存在线程安全问题
方法区的常量是修改不了的,不存在线程安全问题
--一个线程占用一个栈内存
* 局部变量是存储在栈中的,所以局部变量内存空间不会被共享,没有线程安全问题
2.3 线程安全不仅仅存在于JVM中,也发生在数据库中
例如:多个线程共享一张表,如果这些线程都有修改操作就会存在线程安全问题
解决数据库中的线程安全问题:
--第一种:在Java中使用synchronized关键字,线程排队执行,数据库中不会并发
--第二种:行级锁(悲观锁)
--第三种:事务隔离级别,使其串行化
--第四种:乐观锁
...
2.4 Servlet中也有线程安全问题
--一般怎么解决线程安全问题?
* 完成需求尽量用局部变量,不使用成员变量
* 若必须使用成员变量,考虑将该对象变成多例对象,使其一个线程一个java对象,实例变量的内存也不会被共享
* 若必须使用单例,用synchronized关键字让线程排队执行
--解决Servlet的线程安全问题
首先我们要知道Servlet是在单实例多线程的环境下运行的,所以只能用两个方式解决
* 完成需求尽量用局部变量,不使用成员变量
* 用synchronized关键字让线程排队执行
3、资源跳转-转发和重定向
3.1 web系统中资源的跳转有两种方式:
--转发:
forward
代码实现:
request.getRequestDispatcher("/b").forward(request,response);
--转发是在一个项目内部进行资源跳转,在浏览器中请求路径不变,执行结束只有一个请求
--重定向:
redirect
代码实现:
response.sendRedirect(request.getContextPath()+"/b");
//或者说路径是某个webapp项目的资源路径,"部署后的项目名/url-pattern标签中的内容"
--重定向可以是在项目内部跳转,也可以是跨项目跳转,因为路径中可以加项目名。
--原理在
一次请求中请求该Servle对象资源,请求路径:http://localhost:8080/jd/a
执行到上面重定向的java语句后:response.sendRedirect("taobao/b");
将路径"taobao/b"响应给浏览器,浏览器又发送了一个路径为 http://localhost:8080/taobao/b
的新请求。
--重定向是两次请求
--跳转的资源有很多,如Servlet、HTML页面、JSP等等。
--怎么选择这两种跳转方式?
*希望跨app跳转,使用重定向(用的多)
*若上一个资源中的request范围存储了数据,希望在下一个资源中从request取出数据用转发
--为什么重定向用的多
因为重定向可以解决刷新问题(刷新时不用重复执行请求资源的Java程序)
例如我们在请求中提交注册表单数据到服务器,希望将这些数据存储到数据库中。
用if语句判断是否成功,如果存储成功执行跳转到成功的html页面的代码。
使用转发跳转的话,浏览器跳转到成功页面,当我们刷新时就重新发送请求,
由于请求不变
获取request范围中的数据和连接数据将数据存储等等的java程序代码又执行一遍,数据库中就会多出一行记录。
使用重定向跳转,执行重定向跳转后请求路径改变,无论怎么刷新都还是获取哪个成功页面资源的路径。
3.2 创建web项目:idea-servlet-http-10 测试重定向的刷新问题的解决
要注意的是连接数据库的问题,看用idea开发web程序连接数据库的笔记。其中有问题的解析。
代码如下:
SaveServlet.java
package com.servlet.http;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class SaveServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置页面数据类型和编码方式
response.setContentType("text/html;charset=UTF-8");
//
request.setCharacterEncoding("UTF-8");
//获取请求中提交的表单数据
String usercode = request.getParameter("usercode");
String username = request.getParameter("username");
Connection conn = null;
PreparedStatement ps = null;
int count = 0;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mysqlstudy?useSSH=false","root","rong195302");
conn.setAutoCommit(false);
String sql = "insert t_user_3(usercode,username) vlaue(?,?)";
ps = conn.prepareStatement(sql);
ps.setString(1,usercode);
ps.setString(2,username);
count = ps.executeUpdate();
conn.commit();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
if (conn != null) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
}
}finally {
if (ps != null) {
try {
ps.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
if (count==1){
response.sendRedirect("/idea_servlet_http_10_war_exploded/html/result");
}
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<welcome-file-list>
<welcome-file>welcome page</welcome-file>
<welcome-file>html/save.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>save</servlet-name>
<servlet-class>com.servlet.http.SaveServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>save</servlet-name>
<url-pattern>/save</url-pattern>
</servlet-mapping>
</web-app>
save.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>save page</title>
</head>
<body>
<form action="/idea_servlet_http_10_war_exploded/save" method="post">
usercode<input type="text" name="usercode"><br>
username<input type="text" name="username"><br>
<input type="submit" value="save">
</form>
</body>
</html>
result.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>successful page</title>
</head>
<body>
插入数据成功!
</body>
</html>