Java_Web Learn

xekOnerR Sleep.. zzzZZzZ

MySQL 相关

  • 创建一个表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> create table tb_user(
-> id int,
-> username varchar(20),
-> password varchar(32)
-> );

mysql> desc tb_user;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| username | varchar(20) | YES | | NULL | |
| password | varchar(32) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
  • 查询
1
select id,username,password from tb_user where password is not null;
  • 删除
1
2
3
drop table (if exists) 表名;
-- 删除字段:
delete from 表名 where id = xxx; -- 不加条件删除整个表
  • 修改
1
2
3
4
5
6
7
8
9
alter table 表名 rename to 表名; -- 修改表名
alter table 表名 add 表名 数据类型; -- 添加一列
alter table 表名 modify 列名 新数据类型; -- 修改数据类型
alter table 表名 change 列名 新列名 新数据类型; -- 修改列名和数据类型
alter table 表名 drop 列名; -- 删除列

-- 修改列数据
update 表名 set XXX = XXX [where];
update tb_user set password = 'qwer!@34' where username = 'aaa';
  • 插入
1
2
insert into 表名 values();
INSERT into tb_user VALUES(2,'lisi','123456789');

JDBC

Java DataBase Connectivity , 一套驱动数据库的 api,就是通过 java 代码去操作数据库
基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 导入jar 注册驱动  
// Class.forName("com.mysql.cj.jdbc.Driver");

// 获取链接
String url = "jdbc:mysql://localhost:3306/test";
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, username, password);

// 定义sql
String sql = "update tb_user set password = 'qwer!@34' where username = 'lisi'";

// 获取执行sql对象
Statement stmt = conn.createStatement();

try {
// 开启事物
conn.setAutoCommit(false);

// 执行sql
int count = stmt.executeUpdate(sql); // 受影响的行数
System.out.println(count);

// 提交事物
conn.commit();
} catch (Exception e) {
// 回滚事物
conn.rollback();
throw new RuntimeException(e);
}

// 释放资源
stmt.close();
conn.close();

ResultSet 处理结果

1
2
3
4
5
6
7
8
9
10
11
12
13
Connection conn = DriverManager.getConnection(url, username, password);
Statement stmt = conn.createStatement();
String sql2 = "select * from tb_user";
ResultSet rs = stmt.executeQuery(sql2);

while (rs.next()) {
System.out.println(rs.getInt(1));
System.out.println(rs.getString(2));
System.out.println(rs.getString(3));
System.out.println("---------------------------------");
}

rs.close();

预编译 - 防止 sqli , 主要原理是对输入进行转义处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
String url = "jdbc:mysql:///test?useServerPrepStmts=true";  // 需要添加 useServerPrepStmts=true
String username = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, username, password);
// 接收用户输入
String name = "admin";
String pass = "qwe123";

// 预编译
String sql = "select * from demo1 where username = ? and password = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, name); // 第一个?使用name的参数替代
pstmt.setString(2, pass); // 第二个?使用pass的参数替代

ResultSet res = pstmt.executeQuery(); // 直接executeQuery()不需要加参数

if (res.next()) {
System.out.println("Login Success");
} else {
System.out.println("Login Failed");
}

res.close();
pstmt.close();
conn.close();

Maven

专门用于管理和构建 Java 项目的工具

1
2
3
4
5
mvn compile 编译
mvn clean 清理(删除 target)
mvn package 打包
mvn test 测试
mvn install 把package的jar包放在本地仓库

MyBatis

为了简化 JDBC 开发
硬编码直接写在配置文件中以及获取结果集的简化

新建一个 Maven 项目,起名为 MybatisDemo
配置 pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<dependencies>
<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.46</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>

<!-- 添加slf4j日志api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>

</dependencies>

创建 src/main/resources/logback.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>

<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>

</configuration>

创建 src/main/resources/mybatis-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<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:///test?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>

创建实体类
src/main/java 下创建包,并创建 User 类(这个类名根据表的字段来创建)

1
2
3
4
5
6
7
package com.xekoner;  

public class User {
private Integer id;
private String username;
private String password;
........ // 下面省略了 就是PTG生成的标准javabean

创建 Mapper XML 映射文件
和 logback.xml 同级,位于 src/main/resources
id="selectAll" 是唯一的
修改 resultType="com.xekoner.User" , 对应的是 实体类 (Entity/POJO) 的全限定名

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
namespace : 名称空间
-->
<mapper namespace="test">
<select id="selectAll" resultType="com.xekoner.User">
select * from tb_user;
</select>
</mapper>

编写测试类
名字定义为 MyBatisDemo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.xekoner;

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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyBatisDemo {
public static void main(String[] args) throws IOException {
/*加载mybatis的核心配置文件 获取 sqlSessionFactory*/
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

// 获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行sql
List<Object> users = sqlSession.selectList("test.selectAll");
System.out.println(users);

// 释放资源
sqlSession.close();
}
}

Mapper 代理开发

为了解决测试类中 selectAll sql id 存在硬编码的问题

1
2
3
4
5
6
// 获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// 执行sql
List<Object> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
JAVA/attachments/Pasted image 20260120165022.png

遵守以下:

  1. 定义==和 SQL 映射文件同名的 Mapper 接口==,并且将 Mapper 接口和 SQL 接口映射文件放置在同一个目录下
    需要注意创建 Directory 的时候需要用 / 来做分隔符而不是 . ,比如说:com/xekoner/mapper
    Mapper 接口最下面讲JAVA/attachments/Pasted image 20260120170102.png

编译后也可以验证:
JAVA/attachments/Pasted image 20260120170125.png

  1. 设置 SQL 映射文件的 namespace 属性为 Mapper 的接口全限定名
    修改 UserMapper.xml 的命名空间为 Mapper 的接口全限定名
1
<mapper namespace="com.xekoner.mapper.UserMapper">
  1. 在 Mapper 接口中定义方法,方法名就是 SQL 映射文件中 sql 语句的 id,并保持参数类型和返回值类型一致
1
2
3
4
5
6
7
8
9
package com.xekoner.mapper;

import com.xekoner.User;

import java.util.List;

public interface UserMapper {
List<User> selectAll();
}

最后修改 mybatis-config.xml 中的 mapper路径
复制 UserMapper.xml 的路径:
JAVA/attachments/Pasted image 20260120171432.png

1
<mapper resource="com/xekoner/mapper/UserMapper.xml"/>

最后层级图:
JAVA/attachments/Pasted image 20260120171632.png

复制一份 MyBatisDemo ,修改代码并运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

// 获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();

// !!改为获取UserMapper接口的代理对象!!
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectAll();

System.out.println(users);

// 释放资源
sqlSession.close();

流程:
首先获取 sqlSession 和刚刚一样
JAVA/attachments/Pasted image 20260120172352.png

通过 userMapper 去找到代理接口
JAVA/attachments/Pasted image 20260120172432.png

又因为接口同级目录下有同名的映射文件,找到 UserMapper.xml
JAVA/attachments/Pasted image 20260120172549.png

找到之后通过 MyBatisDemo2中的 List<User> users = userMapper.selectAll(); 去找到 UserMapper.xml 中的 id,获取相对应的 sql 语句,返回 List

同时在 mybatis-config.xml 中可以把 mapper resource 改为包扫描的方式减少代码书写量

1
2
3
<mappers>  
<package name="com.xekoner.mapper"/>
</mappers>

Mapper 接口占位符

参数拼接
#{} 为占位符,MyBatis 会把它变成 JDBC 的 ?,然后进行预编译
${} 为拼接符,MyBatis 不管安全性,直接把变量的值粘贴到 SQL 语句里,然后再发给数据库。

1
2
3
4
5
6
7
8
9
10
11
// 新添加一个
<select id="findUser" resultType="com.xekoner.User">
select * from tb_user where username = #{username};
</select>

// 相对应的 UserMapper也需要添加
User findUser(@Param("username") String username);

// 最后修改MyBatisTest中的代码 - 执行方法
User user = UserMapper.findUser("admin");
System.out.println("Find User: " + user);

Tomcat

JAVA/attachments/Pasted image 20260120194306.png
  • IDEA 创建 Maven Web 项目 - 使用骨架JAVA/attachments/Pasted image 20260121153802.png
JAVA/attachments/Pasted image 20260121153851.png

然后补全两个目录
JAVA/attachments/Pasted image 20260121153914.png

  • IDEA 使用 Tomcat - 集成本地 tomcatJAVA/attachments/Pasted image 20260121155106.png

然后部署 war 包
JAVA/attachments/Pasted image 20260121155205.png

运行即可。

  • IDEA 使用 Tomcat - Tomcat Maven 插件
    只支持 tomcat7-maven-plugin, pom.xml 修改 plugin 即可

Servlet

java 提供的一门动态 web 资源开发技术,提供的一个接口
pom.xml 添加

1
2
3
4
5
6
<dependency>  
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

写一个类实现 servlet 接口,配置 WebServlet 注解
@WebServlet("/demo1") 的意思就是配置 URL 路径,如果有访问这个路径,把请求交给 ServletDemo1这个类来处理
JAVA/attachments/Pasted image 20260121165310.png

验证:
JAVA/attachments/Pasted image 20260121165659.png

urlPatterns 规则

urlPatterns 可以配置多个 URL

1
@WebServlet(urlPatterns = {"/demo2", "/demo22"}, loadOnStartup = 1)

精确匹配

1
@WebServlet(urlPatterns = "/user/select", loadOnStartup = 1)

目录匹配 (优先精确匹配)

1
@WebServlet(urlPatterns = "/user/*", loadOnStartup = 1)

扩展名匹配

1
@WebServlet(urlPatterns = "*.do", loadOnStartup = 1)

任意匹配

1
2
3
// 两种都可以
@WebServlet(urlPatterns = "/", loadOnStartup = 1)
@WebServlet(urlPatterns = "/*", loadOnStartup = 1) // 优先级高于 '/'

Servlet 生命周期

init 方法

1
2
3
4
5
6
7
// 初始化方法  
// 调用时机: 默认情况下,Servlet被第一次访问时,调用init方法
// 次数:1
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println(">>>>>>>>>>>>>>>> init !!!");
}
JAVA/attachments/Pasted image 20260121170734.png

修改 init 触发时机 :
JAVA/attachments/Pasted image 20260121171059.png

JAVA/attachments/Pasted image 20260121171253.png

service 方法

1
2
3
4
5
6
7
// 提供服务的方法  
// 每一次Servlet被访问的时候,调用
// 次数:多次
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println(">>>> Doneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.");
}

destroy 方法

1
2
3
4
5
6
7
// 销毁方法  
// 在Servlet被销毁的时候,调用 ; 内存释放/服务器关闭的时候, Servlet对象会被销毁,调用
// 次数:1
@Override
public void destroy() {
System.out.println(">>>>>>>>>>>>>>>> destroy!!!");
}
JAVA/attachments/Pasted image 20260121173406.png

HttpServlet

JAVA/attachments/Pasted image 20260121181034.png

HttpServletRequest req & HttpServletResponse resp

Request 获取请求数据
Response 获取响应数据

获取请求行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求方式
String method = req.getMethod();
System.out.println("req.getMethod() : "+method);

// 获取虚拟目录 - 项目访问路径
String contextPath = req.getContextPath();
System.out.println("req.getContextPath() : "+contextPath);

// 获取url
StringBuffer url = req.getRequestURL();
System.out.println("req.getRequestURL() : " + url);
System.out.println("req.getRequestURL()[toString] : " + url.toString());

//uri
String uri = req.getRequestURI();
System.out.println("req.getRequestURI() : " + uri);

// 获取请求参数
String queryString = req.getQueryString();
System.out.println("req.getQueryString() : " + queryString);
}
JAVA/attachments/Pasted image 20260121201819.png

获取请求头:

1
2
3
// 获取请求头  
String agent = req.getHeader("user-agent");
System.out.println(agent);
JAVA/attachments/Pasted image 20260121202123.png

获取请求体:

1
2
3
4
5
6
7
8
9
// 注意要在doPost方法中写

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求体
BufferedReader br = req.getReader(); // 获得字符输入流,但是不需要关闭,因为req在销毁的时候会自动关闭
String line = br.readLine();
System.out.println(line);
}
JAVA/attachments/Pasted image 20260121202545.png

Request 通用方式获取请求参数

使用 getParameterMap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Get请求逻辑
System.out.println(">>> get");

// 获取所有map的请求集合
Map<String, String[]> map = req.getParameterMap();

// iter 增强for , 获取key
for (String key : map.keySet()) {
// username : xekoner
System.out.print(key + " : ");

// 获取值
String[] values = map.get(key);
for (String value : values) {
System.out.print(value + " ");
}

System.out.println();
}
}
JAVA/attachments/Pasted image 20260121203801.png

使用 getParameterValues 可以获得指定参数的值,以 map 的方式保存为数组

1
2
3
4
5
// 可以通过getParameterValues方法获得指定值, 数组  
String[] usernames = req.getParameterValues("username");
for (String username : usernames) {
System.out.print(username + " ");
}
JAVA/attachments/Pasted image 20260121204150.png

使用 getParameter 获取单个值

1
2
3
// getParameter 只获得单个值 ; 如果传入了两个相同参数的值,只会返回第一个  
String password = req.getParameter("password");
System.out.println(password);
JAVA/attachments/Pasted image 20260121204740.png

Request 请求转发

浏览器请求资源 A -> forward 资源 B -> 响应浏览器

1
2
// 请求转发  
req.getRequestDispatcher("/demo5").forward(req, resp);
JAVA/attachments/Pasted image 20260121205621.png

请求转发中共享数据
Demo4 存储数据:

1
2
// 存储数据  
req.setAttribute("name", "xekoner");

Demo5 获取数据:

1
2
3
// 获取数据  
Object name = req.getAttribute("name");
System.out.println(name);
JAVA/attachments/Pasted image 20260121205932.png

Response

Request 获取请求数据
Response 获取响应数据

Response 完成重定向

浏览器访问 A -> 响应浏览器无法处理【状态码302】,让浏览器去访问 B -> 浏览器访问B
resp1:

1
2
3
4
5
6
7
8
System.out.println(">>> RespDemo1");  

// redirection
// set Response Code to 302
resp.setStatus(302);

// set Response Headder
resp.setHeader("Location", "/tomcat_demo1_war/resp2"); // 这里注意要写全【分版本】

resp2:

1
System.out.println(">>> RespDemo2");
JAVA/attachments/Pasted image 20260121211336.png

也可以通过简化的方式书写 - 【一般写这种】
resp1:

1
2
// redirection  
resp.sendRedirect("/tomcat_demo1_war/resp2");

和转发的区别
重定向是两个不同的域,无法共享数据
转发是同一个域, 可以共享数据

路径问题

路径给服务器使用 - 【转发】,不需要加虚拟目录
路径给浏览器使用 - 【重定向】,需要加虚拟目录

关于重定向获取虚拟路径问题 - 可以使用 req.getContextPath()

1
2
3
4
// redirection  
// 直接通过 getContextPath 获取当前虚拟路径
String contextPath = req.getContextPath();
resp.sendRedirect(contextPath + "/resp2");

Response响应字符&字节数据

响应字符数据

1
2
3
4
5
6
// 获取字符输出流  
PrintWriter writer = resp.getWriter(); // 流不需要关闭
// 设置响应信息
resp.setHeader("Content-Type", "text/html"); // 为了让html标签可以解析,设置响应信息
writer.write(" >>> Resp3 <<< ");
writer.write(" <h1> Resp3 </h1> ");
JAVA/attachments/Pasted image 20260121212549.png

**如果需要输出中文,需要使用 resp.setContentType**

1
2
3
4
// 获取字符输出流  
resp.setContentType("text/html;charset=UTF-8"); // 需要在获取流之前
PrintWriter writer = resp.getWriter();
writer.write("测试用例");
JAVA/attachments/Pasted image 20260121212858.png

响应字节数据
本地图片获取字节流后 copy 到浏览器中显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 读取文件  
FileInputStream fis = new FileInputStream("C://Users/yt134/Desktop/1.png");

// 获取字节输出流, resp流不需要关闭
ServletOutputStream os = resp.getOutputStream();

// 完成流的copy
byte[] buffer = new byte[1024];
int len = 0;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}

// 关闭fis流
fis.close();

也可以通过 commons-io 工具类

  1. pom.xml 导入坐标
1
2
3
4
5
<dependency>  
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.20.0</version>
</dependency>
  1. 修改代码
1
2
3
4
5
6
7
8
9
10
// 读取文件  
FileInputStream fis = new FileInputStream("C://Users/yt134/Desktop/1.png");

// 获取字节输出流, resp流不需要关闭
ServletOutputStream os = resp.getOutputStream();

IOUtils.copy(fis, os);

// 关闭fis流
fis.close();

Filter

过滤器

FilterDemo
定义filter类,实现Filter接口,注意不要选错,选择javax.servlet
JAVA/attachments/Pasted image 20260123141048.png

当配置成

1
2
3
4
5
6
@WebFilter("/*")
....
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(">>>> Filter!!! ");
}

所以说doFilter直接把请求给拦截了并且执行了doFilter中的代码
JAVA/attachments/Pasted image 20260123141328.png

如果要放行需要加上

1
2
// 放行  
filterChain.doFilter(servletRequest,servletResponse);

放行顺序:
执行放行前逻辑
放行
访问资源
执行放行后逻辑

Filter拦截路径配置

1
2
3
4
@WebFilter("/*") // 所有资源
@WebFilter("/user/*")
@WebFilter("*.jsp") // 后缀为jsp都拦截
@WebFilter("index.jsp") // 只有访问特定资源被拦截

Listener

不常用,仅了解
这边以监听资源加载为测试用例

实现监听器 需要创建一个Listener类并且实现相对应的接口

JAVA/attachments/Pasted image 20260123144147.png
1
2
3
4
5
6
7
8
9
10
11
12
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println(">>> Listener is running...");
}

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {

}
}
  • Title: Java_Web Learn
  • Author: xekOnerR
  • Created at : 2026-01-24 11:45:14
  • Updated at : 2026-01-29 18:32:19
  • Link: https://xekoner.xyz/2026/01/24/Java-Web/
  • License: This work is licensed under CC BY-NC-SA 4.0.