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
|
String url = "jdbc:mysql://localhost:3306/test"; String username = "root"; String password = "123456"; Connection conn = DriverManager.getConnection(url, username, password);
String sql = "update tb_user set password = 'qwer!@34' where username = 'lisi'";
Statement stmt = conn.createStatement(); try { conn.setAutoCommit(false); 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"; 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); pstmt.setString(2, pass);
ResultSet res = pstmt.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>
<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; ........
|
创建 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 { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
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 = sqlSessionFactory.openSession();
List<Object> users = sqlSession.selectList("test.selectAll"); System.out.println(users);
|
遵守以下:
- 定义==和 SQL 映射文件同名的 Mapper 接口==,并且将 Mapper 接口和 SQL 接口映射文件放置在同一个目录下
需要注意创建 Directory 的时候需要用 / 来做分隔符而不是 . ,比如说:com/xekoner/mapper
Mapper 接口最下面讲
编译后也可以验证:

- 设置 SQL 映射文件的 namespace 属性为 Mapper 的接口全限定名
修改 UserMapper.xml 的命名空间为 Mapper 的接口全限定名
1
| <mapper namespace="com.xekoner.mapper.UserMapper">
|
- 在 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 的路径:

1
| <mapper resource="com/xekoner/mapper/UserMapper.xml"/>
|
最后层级图:

复制一份 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 = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> users = userMapper.selectAll();
System.out.println(users);
sqlSession.close();
|
流程:
首先获取 sqlSession 和刚刚一样

通过 userMapper 去找到代理接口

又因为接口同级目录下有同名的映射文件,找到 UserMapper.xml

找到之后通过 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>
User findUser(@Param("username") String username);
User user = UserMapper.findUser("admin"); System.out.println("Find User: " + user);
|
Tomcat
- IDEA 创建 Maven Web 项目 - 使用骨架

然后补全两个目录

- IDEA 使用 Tomcat - 集成本地 tomcat

然后部署 war 包

运行即可。
- 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这个类来处理

验证:

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
|
@Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println(">>>>>>>>>>>>>>>> init !!!"); }
|
修改 init 触发时机 :

service 方法
1 2 3 4 5 6 7
|
@Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println(">>>> Doneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee."); }
|
destroy 方法
1 2 3 4 5 6 7
|
@Override public void destroy() { System.out.println(">>>>>>>>>>>>>>>> destroy!!!"); }
|
HttpServlet
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);
StringBuffer url = req.getRequestURL(); System.out.println("req.getRequestURL() : " + url); System.out.println("req.getRequestURL()[toString] : " + url.toString());
String uri = req.getRequestURI(); System.out.println("req.getRequestURI() : " + uri);
String queryString = req.getQueryString(); System.out.println("req.getQueryString() : " + queryString); }
|
获取请求头:
1 2 3
| String agent = req.getHeader("user-agent"); System.out.println(agent);
|
获取请求体:
1 2 3 4 5 6 7 8 9
|
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { BufferedReader br = req.getReader(); String line = br.readLine(); System.out.println(line); }
|
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 { System.out.println(">>> get");
Map<String, String[]> map = req.getParameterMap();
for (String key : map.keySet()) { System.out.print(key + " : ");
String[] values = map.get(key); for (String value : values) { System.out.print(value + " "); }
System.out.println(); } }
|
使用 getParameterValues 可以获得指定参数的值,以 map 的方式保存为数组
1 2 3 4 5
| String[] usernames = req.getParameterValues("username"); for (String username : usernames) { System.out.print(username + " "); }
|
使用 getParameter 获取单个值
1 2 3
| String password = req.getParameter("password"); System.out.println(password);
|
Request 请求转发
浏览器请求资源 A -> forward 资源 B -> 响应浏览器
1 2
| req.getRequestDispatcher("/demo5").forward(req, resp);
|
请求转发中共享数据
Demo4 存储数据:
1 2
| req.setAttribute("name", "xekoner");
|
Demo5 获取数据:
1 2 3
| Object name = req.getAttribute("name"); System.out.println(name);
|
Response
Request 获取请求数据
Response 获取响应数据
Response 完成重定向
浏览器访问 A -> 响应浏览器无法处理【状态码302】,让浏览器去访问 B -> 浏览器访问B
resp1:
1 2 3 4 5 6 7 8
| System.out.println(">>> RespDemo1");
resp.setStatus(302);
resp.setHeader("Location", "/tomcat_demo1_war/resp2");
|
resp2:
1
| System.out.println(">>> RespDemo2");
|
也可以通过简化的方式书写 - 【一般写这种】
resp1:
1 2
| resp.sendRedirect("/tomcat_demo1_war/resp2");
|
和转发的区别
重定向是两个不同的域,无法共享数据
转发是同一个域, 可以共享数据
路径问题
路径给服务器使用 - 【转发】,不需要加虚拟目录
路径给浏览器使用 - 【重定向】,需要加虚拟目录
关于重定向获取虚拟路径问题 - 可以使用 req.getContextPath():
1 2 3 4
|
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"); writer.write(" >>> Resp3 <<< "); writer.write(" <h1> Resp3 </h1> ");
|
**如果需要输出中文,需要使用 resp.setContentType**
1 2 3 4
| resp.setContentType("text/html;charset=UTF-8"); PrintWriter writer = resp.getWriter(); writer.write("测试用例");
|
响应字节数据
本地图片获取字节流后 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");
ServletOutputStream os = resp.getOutputStream();
byte[] buffer = new byte[1024]; int len = 0; while ((len = fis.read(buffer)) != -1) { os.write(buffer, 0, len); }
fis.close();
|
也可以通过 commons-io 工具类
- pom.xml 导入坐标
1 2 3 4 5
| <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.20.0</version> </dependency>
|
- 修改代码
1 2 3 4 5 6 7 8 9 10
| FileInputStream fis = new FileInputStream("C://Users/yt134/Desktop/1.png");
ServletOutputStream os = resp.getOutputStream(); IOUtils.copy(fis, os);
fis.close();
|
Filter
过滤器
FilterDemo
定义filter类,实现Filter接口,注意不要选错,选择javax.servlet

当配置成
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中的代码

如果要放行需要加上
1 2
| filterChain.doFilter(servletRequest,servletResponse);
|
放行顺序:
执行放行前逻辑
放行
访问资源
执行放行后逻辑
Filter拦截路径配置
1 2 3 4
| @WebFilter("/*") @WebFilter("/user/*") @WebFilter("*.jsp") @WebFilter("index.jsp")
|
Listener
不常用,仅了解
这边以监听资源加载为测试用例
实现监听器 需要创建一个Listener类并且实现相对应的接口
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) { } }
|