Servlet 方法介绍
init()
:初始化方法- 调用时机:默认情况下,servlet 被第一次访问时,调用
- 可通过
loadOnStartup
修改
- 可通过
- 调用次数:1次
- 调用时机:默认情况下,servlet 被第一次访问时,调用
service()
:提供服务- 调用时机:每一次Servlet被访问时,调用
- 调用次数:多次
destory()
:销毁方法- 调用时机:内存释放或者服务器关闭的时候,Servlet对象会被销毁,调用
- 调用次数:1次
getServletConfig()
:获取 ServletConfig 对象getServletInfo()
:获取 Servlet 信息(author、version、copyright)
Servlet urlPattern 配置
- 一个 Servlet 可以配置多个 urlPattern
@WebServlet(urlPatterns = {"/demo3", "/demo4"})
- urlPattern 配置规则
- 精确匹配
- 配置路径:
@WebServlet("/demo3")
- 访问路径:
localhost:8080/web-demo/demo3
- 配置路径:
- 目录匹配
- 配置路径:
@WebServlet("/user/*")
- 访问路径:
localhost:8080/web-demo/user/aaa
、localhost:8080/web-demo/user/bbb
- 配置路径:
- 扩展名匹配
- 配置路径:
@WebServlet("*.do")
- 访问路径:
localhost:8080/web-demo/aaa.do
、localhost:8080/web-demo/bbb.do
- 配置路径:
- 任意匹配
- 配置路径:
@WebServlet("/")
、@WebServlet("/*")
- 访问路径:
localhost:8080/web-demo/hehe
、localhost:8080/web-demo/haha
- 配置路径:
- 精确匹配
/
和/*
的区别
- 当我们的项目中的Servlet配置了
/
,会覆盖掉 tomcat 中的 DefaultServlet,当其他的 url-pattern 都匹配不上时都会走这个Servlet- 当我们的项目中配置了
/*
,意味着匹配任意访问路径
优先级:精确路径 > 目录路径 > 扩展名路径 > /* > /
IDEA 模板创建 Servlet
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
#if ($JAVAEE_TYPE == "jakarta")
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;
#else
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
#end
import java.io.IOException;
@WebServlet("/${Entity_Name}")
public class ${Class_Name} extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
中文乱码问题
POST 乱码
getReader()
默认编码是iso-8859-1
- 设置字符输入流的编码为
UTF-8
:request.setCharacterEncoding("UTF-8");
GET 乱码
URL 编码
- 将字符串按照编码方式转为二进制
- 每个字节转为2个16进制并在前边加上%
URL编解码Demo
package com.ruochen.web;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
public class URLDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String username = "张三";
// 1. URL 编码
String encode = URLEncoder.encode(username, "utf-8");
System.out.println(encode);
// 2. URL 解码
String decode = URLDecoder.decode(encode, "ISO-8859-1");
System.out.println(decode);
}
}
%E5%BC%A0%E4%B8%89
å¼ ä¸
tomcat ISO-8859-1 接码我们无法改变,但是我们可以发现 URL 编码数据和接收打的数据字节是一样的(二进制数据 10101xxxx),这就为我们提供了一种思路:我们可以将乱码的数据转换为字节数据(二进制数据),再将二进制字节数据转换为字符串,demo 如下
package com.ruochen.web;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
public class URLDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String username = "张三";
// 1. URL 编码
String encode = URLEncoder.encode(username, "utf-8");
System.out.println(encode);
// 2. URL 解码
String decode = URLDecoder.decode(encode, "ISO-8859-1");
System.out.println(decode);
// 3. 转换为字节数据,编码
byte[] bytes = decode.getBytes("ISO-8859-1");
for (byte b : bytes) {
System.out.print(b + " ");
}
System.out.println();
// 4. 将字节数组转换为字符串,解码
String string = new String(bytes, "utf-8");
System.out.println(string);
}
}
%E5%BC%A0%E4%B8%89
å¼ ä¸
-27 -68 -96 -28 -72 -119
张三
servlet demo
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 解决post乱码 getReader() 默认编码是 iso-8859-1
request.setCharacterEncoding("UTF-8"); // 设置字符输入流的编码
String username = request.getParameter("username");
System.out.println("解决乱码前:" + username);
// GET 获取参数的方式:getQueryString()
// 乱码原因:tomcat 进行URL解码,默认的字符集ISO-8859-1
// 1. 先对乱码进行编码,转为字节数组
// byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1);
// 2. 字节数组解码
// username = new String(bytes, StandardCharsets.UTF_8);
username = new String(username.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
System.out.println("解决乱码后:" + username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
Tomcat 8 之后,已将GET请求乱码问题解决,设置默认的解码方式为 UTF-8
路径问题
- 明确路径谁使用?
- 浏览器使用:需要加虚拟目录(项目访问路径)
- 服务端使用:不需要加虚拟目录
- 练习
- <a href = "路径">:加虚拟目录
- <form action="路径">:加虚拟目录
- req.getRequestDispatcher("路径"):不需要加虚拟目录
- resp.sendRedirect("路径"):需要加虚拟目录
Response 响应字符数据
- 使用 Response 对象获取字符输出流:
PrintWriter writer = resp.getWriter();
- 写数据:
write.write("aaa");
- 可通过设置 header 指定类型:
resp.setHeader("content-type", "text/html");
- 流不需要关闭,resp 对象销毁的时候会自动关闭
- 中文乱码,设置流的编码:
resp.setContentType("text/html;charset=utf-8");
Response 响应字节数据
- 通过 Response 对象获取字节输出流:
ServletOutputStream outputStream = resp.getOutputStream();
- 写数据:
outputStream.write(字节数据);
- 案例
package com.ruochen.web;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.FileInputStream;
import java.io.IOException;
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 读取文件
FileInputStream fis = new FileInputStream("C:\\Users\\ruochen\\Desktop\\离雨.jpg");
// 2. 获取 response 字节输出流
ServletOutputStream os = response.getOutputStream();
// 3. 完成流的 copy
byte[] buff = new byte[1024];
int len = 0;
while((len = fis.read(buff)) != -1) {
os.write(buff, 0, len);
}
fis.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
- 我们可以使用
commons-io
工具类简化上述操作 - 导入坐标:
pom.xml
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>
上述循环遍历代码可简化为如下
IOUtils.copy(fis, os);
用户登录案例
准备工作
login.html
放到 webapp 目录下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
<link href="css/login.css" rel="stylesheet">
</head>
<body>
<div id="loginDiv">
<form action="/web-demo/loginServlet" method="post" id="form">
<h1 id="loginMsg">LOGIN IN</h1>
<p>Username:<input id="username" name="username" type="text"></p>
<p>Password:<input id="password" name="password" type="password"></p>
<div id="subDiv">
<input type="submit" class="button" value="login up">
<input type="reset" class="button" value="reset">
<a href="register.html">没有账号?点击注册</a>
</div>
</form>
</div>
</body>
</html>
login.css
* {
margin: 0;
padding: 0;
}
html {
height: 100%;
width: 100%;
overflow: hidden;
margin: 0;
padding: 0;
background: url(../imgs/Desert.jpg) no-repeat 0px 0px;
background-repeat: no-repeat;
background-size: 100% 100%;
-moz-background-size: 100% 100%;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
#loginDiv {
width: 37%;
display: flex;
justify-content: center;
align-items: center;
height: 300px;
background-color: rgba(75, 81, 95, 0.3);
box-shadow: 7px 7px 17px rgba(52, 56, 66, 0.5);
border-radius: 5px;
}
#name_trip {
margin-left: 50px;
color: red;
}
p {
margin-top: 30px;
margin-left: 20px;
color: azure;
}
input {
margin-left: 15px;
border-radius: 5px;
border-style: hidden;
height: 30px;
width: 140px;
background-color: rgba(216, 191, 216, 0.5);
outline: none;
color: #f0edf3;
padding-left: 10px;
}
#username{
width: 200px;
}
#password{
width: 202px;
}
.button {
border-color: cornsilk;
background-color: rgba(100, 149, 237, .7);
color: aliceblue;
border-style: hidden;
border-radius: 5px;
width: 100px;
height: 31px;
font-size: 16px;
}
#subDiv {
text-align: center;
margin-top: 30px;
}
#loginMsg{
text-align: center;color: aliceblue;
}
创建 db1
数据库,创建 tb_user
表,创建 User
实体类
-- 创建数据库
create database db1 character set utf8;
use db1;
-- 创建用户表
CREATE TABLE tb_user(
id int primary key auto_increment,
username varchar(20) unique,
password varchar(32)
);
-- 添加数据
INSERT INTO tb_user(username,password) values('zhangsan','123'),('lisi','234');
SELECT * FROM tb_user;
package com.ruochen.pojo;
public class User {
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
导入MyBatis 坐标,MySQL 驱动坐标
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
创建 mybatis-config.xml
核心配置文件,UserMapper.xml
映射文件,UserMapper
接口
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--起别名-->
<typeAliases>
<package name="com.ruochen.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true"/>
<property name="username" value="root"/>
<property name="password" value="ruochen666"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--扫描mapper-->
<package name="com.ruochen.mapper"/>
</mappers>
</configuration>
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruochen.mapper.UserMapper">
</mapper>
UserMapper.java
package com.ruochen.mapper;
public interface UserMapper {
}
目录树如下
流程
UserMapper.java
package com.ruochen.mapper;
import com.ruochen.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
/**
* 根据用户名和密码查询用户对象
* @param username
* @param password
* @return
*/
@Select("select * from tb_user where username= #{username} and password = #{password}")
User select(@Param("username") String username, @Param("password") String password);
}
UserServlet.java
package com.ruochen.web;
import com.ruochen.mapper.UserMapper;
import com.ruochen.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 接收用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 2. 调用 MyBatis 完成查询
// 2.1 获取 SqlSessionFactory 对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.2 获取 SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 2.3 获取 Mapper
UserMapper userMapper = sqlSession.getMapper(UserMa