JavaWeb
Tomcat 配置
Tomcat 是 web 服务器。
默认端口号:8080
可以直接使用 bin/startup.bat 启动
配置文件为 conf/server.xml
一开始 Tomcat 访问不了的原因是放在了 x86 文件夹下
网站的访问
- 键入 url
- 检查本机 system32\drivers\etc\hosts 配置文件下查看是否存在该 url 的映射,如果存在直接返回 IP
- 访问 DNS 服务器,获得 IP
使用 Tomcat 发布一个网站
将 html 放在指定的 web 应用文件夹下
网站结构
1 | --webapps: // Tomcat 服务器的 web 目录 |
HTTP
超文本传输协议,是一个简单的请求-响应协议。
- TCP
- port:80
HTTPS:安全的超文本传输协议
HTTP request
HTTP response
状态码:
- 200:成功
- 404:找不到
- 3**:重定向
- 5**:服务器代码错误
Maven
为什么要学习 Maven
- JavaWeb 开发中,需要使用大量的 jar 包,我们需要手动导入
- Maven 是一个自动导入和配置 jar 包的工具
Maven 介绍
Maven 的核心思想:约定大于配置
1 | bin: 可执行文件 |
IDEA 中使用 Maven
- 创建 MavenWeb 项目
上面图片的 groupId 配置错误(
- IDEA 中的 Maven 设置
Spring 中可能会使用 IDEA 自带的 Maven,所以我们可能需要在 IDEA 中配置 Maven。
Maven 项目结构
1 | --mian |
在 IDEA 中配置 Tomcat
左上角配置启动环境即可
Maven Webapp 项目结构
1 | -Lifecycle // maven 命令行操作 |
pom.xml 文件
用于配置 maven 项目。只要将需要导入的包放在 dependencies 下面即可。
子项目无法识别父项目的时候,子模块加上
1 | <parent> |
即可
Servlet
Servlet 简介
- 用于开发动态 Web 的技术
把实现了 Servlet 接口的 Java 程序叫做 Servlet
HelloSverlet
Servlet 接口有两个默认的实现类:HttpServlet
构建 Maven 项目,删掉里面的全部东西,将依赖全部导入主工程
将 Servlet 建在 Module 中
关于 Maven 父子工程的理解:
在父项目中建立一个 module,类似与继承
Maven 环境优化
- 修改 web.xml
- 将 maven 环境搭建完整
实现 Servlet 程序
- 编写一个实现 Servlet 接口的类
- 继承 HttpServlet
编写 Servlet 的映射
为什么需要映射
JAVA 程序需要使用浏览器访问,浏览器需要连接 Web服务器,所以我们需要 Web 服务器中注册我们写的 Servlet,并且给他一个浏览器能够访问的路径。
用户需要通过浏览器来访问 Web 服务器中的 Servlet。所以我们需要在 Web 服务器中注册 Servlet
1
2
3
4
5
6
7
8
9<servlet>
<servlet-name>hello</servlet-name> // 3
<servlet-class>com.auggie.Servlet.HelloServlet</servlet-class> // 4
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name> // 2
<url-pattern>/hello</url-pattern> // 1
</servlet-mapping>Java 程序需要 servlet 注册,给定一个 servlet 名字
然后将 servlet - name 映射到 url - pattern 上面
配置 Tomcat
一开始使用的 Tomcat 是 10 版本,版本太高了(,导致版本不兼容
Servlet 接口的实现
Servlet interface
1 | void init(ServletConfig var1) throws ServletException; |
GenericServlet
通用小服务程序
1 | public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException; |
HttpServlet
已经实现了 service 方法,我们只需要重写 service 调用的子方法
1 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException; |
Servlet 原理
Web 服务器收到浏览器请求之后,会调用 Servlet
mapping 优先级:指定了固有映射的优先级最高。
ServletContext
背景:登陆的时候,一个登陆全部都登陆了
Web 容器在启动的时候,为 Web 程序都创建一个对应的 ServletContext 对象,代表当前的 Web 应用。
应用:
共享数据(不同 Servlet 之间的数据通信)
在这个 Servlet 中的数据可以在另外一个 Servlet 中访问。
转发
1
2
3
4
5
6
7
8
9
10
11
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
System.out.println("dispatch");
servletContext.getRequestDispatcher("/hello").forward(req, resp);
System.out.println("finish");
}
/*
1. 转发之后,会返回
2. 需要使用 forward(req, resp) 方法来执行跳转
*/
注意事项:
如果从 ServletContext 中读取一个不存在的对象,结果为空。
设置 resp 的字符集即可解决乱码问题。
1
2resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
Response
响应状态码
响应体
1
2
3ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;常见应用
- 向浏览器输出消息
- 下载文件
- 获取文件的绝对路径
- 获取文件名,可以使用 trick 获得
- 设置响应头 + fileName
- 创建 FileOutputStream, + realPath
- 创建 OutputStream
- 创建 buffer
- 将 in 读取到 buffer 中,再将 buffer 中的数据读取到 out 中
- 关闭流对象
File -> FileOutputStream -> Buffer -> OutputStream -> Client
1 |
|
总结:需要掌握 resp 的状态头,流对象的使用。
3. **验证码,后端实现**
如何实现后台刷新
resp.setHeader(“refresh”, “5”);
在内存中创建图片
BufferedImage
创建随机数
- random
- 将 int 转化为 String 类
- “” + int
- String.valueOf(int)
- 保证随机数一定是等长的
- 使用 StringBuffer 对象
实现重定向
页面跳转,该资源请求另外一个 Web 资源
重定向的路径从项目目录开始,跳转从当前目录开始
1
2this.getServletContext().getRequestDispatcher("/down").forward(req, resp);
resp.sendRedirect("/resp/down");
Request
1 | ${pageContext.request.contextPath} |
1 | req.setCharacterEncoding("utf-8"); // 防止乱码 |
会话技术
作用:用于解决 HTTP 协议的无状态性。
从打开浏览器访问某个网站,到关闭浏览器的过程,称为一次会话。会话技术是指在会话中,帮助服务器记录用户状态和数据的技术。
保存会话的两种会话技术
- Cookie 客户端会话技术
- Session 服务器会话技术
Cookie
定义:Cookie 属于客户端会话技术,它是服务器发送给浏览器的小段文本信息,存储在客户端浏览器的内存中或硬盘上。当浏览器保存了 Cookie 后,每次访问服务器,都会在 HTTP 请求头中将这个 Cookie 回传给服务器。
Cookie 中存的是键值对。可以使用 getCookie 方法获得全部的 Cookie 数组。然后使用 getName()
和 getValue()
获取单个 Cookie 的值。
setMaxAge(int expiry)
以秒为单位。
String 转化为 Date 对象
1
2
3
4String value = it.getValue();
Long tmp = Long.parseLong(value);
Date date = new Date(tmp);
System.out.println(date);Date 转化为 String 输出
SimpleDateFormat
访问其他页面的时候,会把 cookie 带过来。
缺点:
- 在 HTTP 请求中,Cookie 是明文传递的,容易泄露用户信息,安全性不高。
- 浏览器可以禁用 Cookie,一旦被禁用,Cookie 将无法正常工作。
- Cookie 对象中只能设置文本(字符串)信息。
- 客户端浏览器保存 Cookie 的数量和长度是有限制的。
Session
Session 虽然属于服务端会话技术,但是它的实现离不开客户端浏览器和 Cookie 的支持。
过程:
- 当客户端第一次请求会话对象时,服务器会创建一个 Session 对象,并为该 Session 对象分配一个唯一的 SessionID(用来标识这个 Session 对象);
- 服务器将 SessionID 以 Cookie(Cookie 名称为:“JSESSIONID”,值为 SessionID 的值)的形式发送给客户端浏览器;
- 客户端浏览器再次发送 HTTP 请求时,会将携带 SessionID 的 Cookie 随请求一起发送给服务器;
- 服务器从请求中读取 SessionID,然后根据 SessionID 找到对应的 Session 对象。
在 pom.xml 中设置 Session 存活时间
以分钟为单位,默认是 30 min。Session-time 是 0 或者负数的时候,表示会话不会过期。
1 | <session-config> |
Cookie 和 Session 的区别
Servlet Session的使用 (biancheng.net)
上面总结的很全面
MVC 三层架构
Module View Controller 模型视图控制器
Module:
- 业务处理(Service):实现业务逻辑
- 数据持久层(DAO):主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此
View:
- 展示数据
- 发起 Servlet 请求
Controller:
- 接受用户请求
- 交给业务层处理
- 控制视图跳转
Demo:
- 接受用户登陆请求(controller)
- 处理用户用户请求(controller)
- 交给业务层,判断是否合法(Module)
- 交给 DAO 层查询 DB 是否合法
Filter
能够对 Servlet 容器传给 Web 资源的 request 对象和 response 对象进行检查和修改。
- 在 Web 资源被访问前,检查 request 对象,修改请求头和请求正文,或对请求进行预处理操作。
- 将请求传递到下一个过滤器或目标资源。
- 在 Web 资源被访问后,检查 response 对象,修改响应头和响应正文。
作用:
- 处理中文乱码
- 登陆验证
注意事项:
- 过滤器需要注册
- doFilter 需要下传,如果不写程序将在这里停止。
- 过滤器在 Web 服务器启动的时候,初始化
- 过滤器在 Web 服务器停止的时候,销毁
过滤经过 url 的全部请求
1 | <filter> |
1 | filterChain.doFilter(servletRequest, servletResponse); // 不写程序直接停止运行 |
Filter 和监听器的应用
用户登陆之后才能看到主页,用户注销之后不能进入主页
1 | -view |
在 home.jsp 中重定向
使用过滤器实现
转化之后,才能获得 Session。
过滤器注册在什么地方?主页下面的一切,主页和其他页面分开
实现用户等级 id name level
小结:
过滤器实现拦截需要将网页放在不同的路径下。
小结
- 一般方法
servletResponse.setCharacterEncoding("utf-8");
设置编码servletResponse.setContentType("text/html");
设置浏览器展示样式
- rep 常用方法
getSession()
getCookie()
getParameter()
getParameterValues()
- Session 常用方法
getAttribute(String)
setAttribute(String, Object)
removeAttribue(String)
invalidate()
sendRedirect(Stirng Absoluteurl)
- Cookie 常用方法
getName(String)
getValue(String)
- resp 常用方法
getWriter()
getOutputStream()
addCookie(String, String)
- ServletContext 常用方法 this.getServletContext()
getAttribute(String)
setAttribute(String)
getRequestDispatcher(String url).forward(req, resp)
- Filter
implements Filter
doFilter
JDBC
流程
- 加载驱动,生成 DriverManager 对象
- 通过 DriverManager 对象,生成数据库连接对象 connection
- 通过 connection 对象,生成执行环境对象 statement
- 通过 statement 对象,生成 resultSet 对象
加载 JDBC
1 | Class.forName("com.mysql.jdbc.Driver"); |
连接数据库
创建数据库连接对象
1 | String url = "jdbc:mysql://IP:Port/DATABASE"; |
配置 properties 文件
- 编写 properties 文件
- 使用
ClassName.class.getClassLoad().getResourceAsStream("file")
获取文件字节流 - 初始化,创建
Properties
对象读取字节流p.load(InputStream)
- 读取数据
p.getProperty("name")
不要加空格,不要加双引号
1 | driver=com.mysql.jdbc.Driver |
从其他文件读取 .properties 文件
1 | // 通过类名访问文件加载器 |
增删改查基本步骤
- 创建连接对象 Connection
- 写 SQL 语句
- 获取 PerparedStatement 对象
- 修改 PerparedStatement 传入参数
- 执行 SQL 语句,得到结果集
- 处理结果集
- 关闭资源
查询
1 | // 创建执行环境 |
插入
1 | // 创建环境 |
插入时间类型:
因为 java.util.Date 和 java.sql.Date 不同,所以需要相互转化。
Date(year, month, day)
Date(Long )
MyBatis
Mybatis3 简介
什么是 Mybatis
- MyBatis 是一款优秀的持久层框架。
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
配置相关:
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
持久层
持久化
数据持久化,将数据存在数据库中。
持久化就是将程序的数据在持久状态和瞬时状态转化的过程
为什么需要持久化:内存断点即失,内存太贵了。存在一些数据不能丢失¥
持久层
Dao层,Service层,Controller层
- 完成持久化工作的代码块
- 层是界限明显的
为什么需要 mybatis,而不是直接使用 JDBC
- 传统 JDBC 代码太复杂
- 用于简化 JDBC 的框架
- 自动化
第一个 Mybatis 程序
搭建环境 database,普通 maven
导入 mybatis
- mybatis
- mysql
- junite
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<dependencies>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.8</version>
</dependency>
</dependencies>编写代码
创建一个 module
编写 mybatis 核心配置文件
在 resource 下建立一个 mybatis-config.xml 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<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://47.101.155.92:3306/idea?useSSL=true"/>
<property name="username" value="bus"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/auggie/dao/UserMapper.xml"/>
</mappers>
</configuration>编写 mybatis 工具类(类似 connection 对象)
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
29package com.auggie.utils;
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;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
// 获取 SqlSessionFactory 对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
System.out.println("配置成功");
} catch (IOException e) {
System.out.println("配置失败");
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}编写代码
- 实体类 pojo
- Dao 接口
- 接口实现类
1
2
3
4
5
6
7
8
9
10
<--接口路径 + 函数名称 + 返回对象的泛型-->
<mapper namespace="com.auggie.dao.UserDao">
<select id="getUserList" resultType="com.auggie.pojo.User">
SELECT * FROM idea.user;
</select>
</mapper>
测试
junite 测试
- 需要注册 Mapper
- Maven 过滤掉 .xml 文件,(maven 资源导出失败)
步骤:
- 创建 SqlSession 对象
- 创建接口对应的 mapper
- 调用接口定义的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
遇到的问题:
- 如果文件在 resources 目录下,可以直接使用文件名访问到该文件
- mapper 中指定 .xml 文件需要使用 /classes 下的路径
- 需要更新到最新版本
- Maven 过滤掉除了 resources 目录下的 .xml 文件。
- .xml 中不能添加中文(
小结:
- 在 pojo 中创建实体类
- 在 Dao 中创建接口 XXX
- 设置 XXX.xml,设置 namespace,对应函数,返回的实体类,SQL 语句
- 在 mybatis-config.xml 中,创建 mapper
CRUD
Create
- 在 xml 申明中
parameterType = ""
传递参数使用#{paraName}
,需要指定具体的类。 - 需要指定具体的 select, insert, update, delete
- CUD 需要提交事物,否则不成功。
sqlSession.commit()
总结:
编写
- 编写接口
- 编写 mapper 中的 SQL 语句
- xml 中配置 namespace
使用
- 创建 SqlSession 对象
- 创建接口对象 sqlSession.getMapper(Interface.class)
- 调用接口中的函数
- 提交事务
- 关闭 sqlSession 对象
Map && 模糊查询 (LIKE)
解决传递全部属性的问题(我只需要少数的几个参数就可以修改,不需要全部属性)
map 传递参数的好处:
- 可以随意传递参数名
- 不需要全部参数
模糊查询:
where name like "%"#{name}"%"
where name like #{name} // name == "%name%"
XML 配置解析
environment
可以配置多套环境,但是每次只能选用一套。
事物管理器 transactionManager
1. JDBC
- MANAGER
dataSource
1
2
3
4
5
6
7
8
9
10
11<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://47.101.155.92:3306/idea?useSSL=true"/>
<property name="username" value="bus"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>properties
编写 .properties 文件,在 mybatis-config.xml 中导入该文件
- 可以直接引入外部配置文件(优先使用)
- 可以在 xml 中直接编写
typeAlias
它仅用于 XML 配置,意在降低冗余的全限定类名书写。可以在所有 XML 中使用
在 XML 文件中配置。(实体类少的时候)
1
2
3
4
5
6
7
8<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>在 interface 文件中配置。(实体类多的时候)
1
2
3
4
5<typeAliases>
<package name="domain.blog"/>
</typeAliases>
@Alias("author")在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。
setting
- mapUnderscoreToCamelCase 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn.
- logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。
ResultSet 结果集映射
用于解决实体类和数据库属性字段名字不同的问题。
解决方法:
SQL 中取别名
ResuletSet 结果集映射
自定义映射,如果是组合类对象如何解决?
日志
日志工厂
将异常的 SQL 输出出来。
STDOUT_LOGGING
LOG4J
可以使用配置文件进行配置
分页
为什么需要分页?
- 数据量太大,需要分页展示
- 减少数据的处理量
1 | SELECT * FROM user LIMIT startIndex, pageSize; |
接口
1
List<User> getUserListByLimit(HashMap<String, Integer> map);
Mapper.xml
1
2
3<select id="getUserListByLimit" parameterType="map" resultType="user">
SELECT * FROM user LIMIT #{startIndex}, #{pageSize};
</select>测试
注解开发
面向接口编程
- 解耦
- 定义与实现的分离
1 | package org.mybatis.example; |
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。
因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
1 | User getUserByID(int id); |
使用注解实现 CUD 的时候,需要使用 autoCommit = true
@Param
- 基本类型的参数或则 String 类型,需要加上
- 引用类型不需要加
Lombok
自动生成方法。
可以放在类上,也可以放在字段上
@Data 无参构造、Set、get、toString、hashCode、equals
@AllArgsConstructor 创建含有全部参数的构造方法
@NoArgsConstructor 创建无参构造
1 |
|
复杂查询环境的搭建
数据库结构:
Student 含有 Teacher 的外键
复杂属性的查询
- 对象:association
- 集合:collection
多对一(学生 -> 学生 + 老师)
查询所有学生信息,以及对应老师的信息
结构中包含另一个类
javaType
表示一个具体的对象
子查询
里面的 properties 都是 Student 的属性
内嵌
select
字段,调用其他函数,函数的入口是column
1
2
3
4
5
6
7
8
9
10
11
12
13
14<resultMap id="StudentTeacher" type="com.auggie.pojo.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="com.auggie.pojo.Teacher"
select="getTeacher"/>
</resultMap>
<select id="getStudentList" resultMap="StudentTeacher">
SELECT * FROM mybatis.student;
</select>
<select id="getTeacher" resultType="com.auggie.pojo.Teacher">
SELECT * FROM mybatis.teacher WHERE id = #{id};
</select>连表查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<resultMap id="StudentTeacher2" type="com.auggie.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="com.auggie.pojo.Teacher">
<result property="name" column="tname"/>
<result property="ttid" column="id"/>
</association>
</resultMap>
<select id="getStudentList2" resultMap="StudentTeacher2">
SELECT s.id sid,
s.name sname,
t.id ttid,
t.name tname
FROM mybatis.student s,
mybatis.teacher t
WHERE s.tid = t.id;
</select>
一对多(老师 -> 老师 + 学生)
查询一个老师教授的全部学生
类中包含一个集合
- 连表查询
1 | <resultMap id="TeacherStudent" type="com.auggie.pojo.Teacher"> |
- 子查询
动态 SQL
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
根据不同的条件获得不同的 SQL 语句。
都需要一个永真的条件开始
sql 标签
用于复用一些 sql
片段。
- 最好不要包含
where、set
标签 - 不要包含太复杂的 SQL
创建
1 | <sql id="if-id-name"> |
使用
1 | <include refid="if-id-name"></include> |
if
- 使用 map 传入参数
- 使用 state = ‘ACTIVE’
1 | <select id="getStudent" parameterType="map" resultType="com.auggie.pojo.Student"> |
choose
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。
针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
choose <=> switch
when <=> if, else if
otherwise <=> default
1 | <select id="getStudent" parameterType="map" resultType="com.auggie.pojo.Student"> |
where, trim, set
where
用于解决出现前置 AND,OR 的情况
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
使用
1 | <select id="getStudent" parameterType="map" resultType="com.auggie.pojo.Student"> |
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。
set
用于解决动态更新语句的后置 ,
的情况。投影不能使用
1 | <update id="updateAuthorIfNecessary"> |
trim
1 | <trim prefix="WHERE" prefixOverrides="AND |OR "> |
用于自定义匹配。
foreach
用于解决不定长条件。
这个元素也不会错误地添加多余的分隔符,看它多智能!
例如:需要查询学生 id 为 [1,2,3,…] 学生的全部信息
1 | SELECT * FROM mybatis.student WHERE (id = 1 OR id = 2 OR id = 3) |
实现:
既可以用在选择中,也可以用在投影中。但是在投影中,需要使用 ${} 不知道为什么(
1 | <select id="get" parameterType="map" resultType="com.auggie.pojo.Student"> |
当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。
当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
foreach 组合条件条件查询。
1 | public List<File> getFileWithAttribute(int limit); List<String> departmentList, |
1 | <select id="getFileWithAttribute" resultType="com.auggie.experi.pojo.File"> |
缓存
问题:查询连接数据库,消耗资源
可以将一次查询的结果缓存下来,再次查询相同数据的时候,直接取走缓存中的数据。提高查询效率,解决高并发系统的性能问题。
MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。
1 | <cache |
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
可用的清除策略有:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
默认的清除策略是 LRU。
flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。
size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。
readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。
Springboot
javaJavaBean
JavaBean 是一种实体类
JavaBean 有特定的写法:
- 必须有无参构造
- 属性必须私有化
- 必须有 get / set 方法
一般用于与数据库的字段做映射 ORM。Object Relational Mapping
ORM:对象属性映射
- 表 -> 类
- 字段 -> 属性
- 行记录 -> 对象
Spring MVC 前置知识
Controller & ResquestMapping
本质还是 Servlet
传递参数需要使用 Model 对象,调用 addAttribute
方法
1 | // 利用注解在 Spring 中自动注册 Controller |
Restful 风格
使用 Restful 风格可以让 URL 变得结构清晰
不使用 Restful:
1 | http://localhost:8080/hello?a=1&b=2 |
使用 Restful:
1 | http://localhost:8080/hello/1/2 |
实现 Restful 风格:
需要使用 @PathVariable
注解
1 |
|
实现转发和重定向
1 | // forword |
获取前端数据 & 数据回显
servlet 中使用 getParam 参数
获取前端数据
通过 URL 之后的参数获取。
Restful
@RequsetMapping(“/hello/{a}/{b}”)
@ParamVarible
使用 ?传递参数
@RequestParam
1
http://localhost:8080/hello/1/2
如果前端传递参数和接受的参数不同的时候,可以使用 @RequestParam("alias")
,最好都加上
前端传递 Class
直接使用 JavaBean,即可接受,接受失败返回 null
如果为添加表单的话,建议使用 POST 方法,@PostMapping 这样就可以接收到 Class 参数。并且顺序无关。
数据回显
详解SpringMVC如何进行数据回显 - 编程语言 - 亿速云 (yisu.com)
- 使用参数
- 使用 ModelMap
- 使用 Model
微服务阶段
- JavaSE :oop
- Mysql :持久化
- HTML, CSS, JS:视图层
- JavaWeb :开发 MVC 三层架构的网站
- SSM :Spring + Spring MVC + MyBatis 框架,简化开发流程,配置较为复杂
war:tomcat 运行
jar:内嵌 tomcat
该怎么学
Spring Boot:
- 是什么
- 配置如何编写,yaml
- 自动装配原理
- 集成 Web 开发,SSM
- 集成数据库 Druid
- 分布式开发
- 接口文档
- 任务调度
什么是 Spring Boot
什么是 Spring
容器,为了解决企业级应用开发的复杂性创建的。
什么是 Spring Boot
JavaWeb:Servlet + Tomcat
Spring Boot 就是一个 JavaWeb 的框架。约定大于配置。
什么是微服务
将服务拆分成很多小的模块。
第一个 Spring Boot 程序
Controller 层用来写接口
通过 Maven 的 Package 就可以实现打包。使用 java -jar XXX.jar
就可以运行。
自动装配原理
pom.xml 中 spring-boot-dependencies 包含了核心依赖。因此编写依赖的时候,不需要指定具体的版本。
主函数
1 | // 标注这个类是一个 SpringBoot 的应用 |
SpringBoot 配置文件
application.*
什么是 YAML 文件
修改 SpringBoot 自动配置的默认值
1 | # 1. 普通的 key-value |
YAML 可以直接给实体类注入值
1
2
3
4
5
6
7
8
9
public class Dog {
private String name;
private Integer age;
}
private Dog dog;1
2
3dog:
name: dogdog
age: 12
可以包含${random.int} ${random.uuid}
来产生随机数
${person.hello: hello}
如果 person.hello
存在,则为 person.hello
;不然为 hello
- 一般使用 @Value 给实体类赋值
可以使用 YAML 配置端口:
1 | server: |
JSR303 校验
应用:后端实现前端 input
标签中的校验功能。
例如:url,email 的校验。
需要导入依赖:
1 | <dependency> |
添加上注解即可:
1 |
|
如果不正确,则会报错。
多环境配置以及配置文件位置
application.yaml
文件可以放在:(优先级从高到低)
SpringBoot Web 开发
Controller:@Controller
Dao:@Repository,使用 Dao 层,需要加上 @Autowired 注解
静态资源的导入
放在 resources/[public, resources, static]
都行
其中优先级从高到低
- resources:存放上传文件
- static:存放静态资源,图片
- public:存放公共资源,大家都会访问的 js
首页和图标的定制
templates 下的页面,只能通过 Controller 下面跳转。
首页的定制
自定义 index.html
即可
图标自定义
- 创建
/**/favicon.ico
- 在 YAML 中创建
spring.mvc.favicon.enable: false
模板引擎
写一个模板,可以生成动态页面/
Maven 依赖:
1 | <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf --> |
将 html 存放在 templates 目录下即可。
1 | xmlns:th="http://www.thymeleaf.org" |
Thymeleaf 常见语法
项目实践
首页搭建
首页跳转的实现
可以使用 RequestMappering 跳转
也可以使用 MvcConfig 来配置
1
2
3
4
5
6
7
8
9
10
11
public class MyMVCConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
}
}
首页配置
- 将 html 放在 templates 下,将 css, js 放在 static 下
- html 中需要加入 thymeleaf 的标签,需要加上 thymeleaf 的超链接标签
首页密码登陆
1 | <p th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p> |
当有信息回写的时候,才会触发。
配置拦截器
实现 HandlerInterceptor
的接口。
登陆成功之后,应该有用户的 session。
- 拦截器代码:
1 | public class LoginHandlerInterceptor implements HandlerInterceptor { |
需要在 login 代码中添加
HttpSession session
,然后给 session 添加值需要在 MvcConfig 中配置拦截器
1
2
3
4
5
6
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/sys/*", "/servlet/*")
.excludePathPatterns("/servlet/login");
}html 取出 session 的值,需要
<p>hello, [[${session.userInfo}]]</p>
,使用 [[${}]] 来操作。
CRUD
R
1 | <table class="table table-strip table-sm"> |
CUD
需要使用 form 表单。如果使用 JavaBean 传递参数的话,建议使用 @PostMapping 接受参数。
1 |
|
跳转、action、重定向全部都是经过 servlet
处理 404 / 500
只需要在 templates
下建立 error
文件夹。然后将 404 / 500 放在该文件夹下即可。
集成数据库
添加驱动
配置数据库连接文件
1
2
3
4
5
6spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://47.101.155.92:3306/mybatis?useSSL=true
username: bus
password: 123如果出错的话,需要添加时区。
自动产生对象
datasource
1
2
3
4
5
6
7
DataSource dataSource;
void contextLoads() {
System.out.println(dataSource.getClass());
}整合 Druid 数据源
导入 Maven
1
2
3
4
5
6<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>配置 YAML
1
2
3
4
5
6
7spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://47.101.155.92:3306/mybatis?useSSL=true
username: bus
password: 123
type: com.alibaba.druid.pool.DruidDataSource配置 Druid
不太想配((((
MyBatis
Maven 配置,帮助 Spring Boot 快速配置 MyBatis
1
2
3
4
5
6
7<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>application.yaml
1
2
3
4
5
6
7
8
9
10spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://47.101.155.92:3306/mybatis?useSSL=true
username: bus
password: 123
# 整合 mybatis
mybatis:
type-aliases-package: com.example.databases.pojo
mapper-locations: classpath:mybatis/Mapper/*.xmlUserMapper.xml
1
2
3
4
5
6
7
8
9
<mapper namespace="com.example.databases.Mapper.UserMapper">
<select id="queryStudentList" resultType="Student">
SELECT * FROM mybatis.student
</select>
</mapper>DAO:UserMapper 接口
1
2
3
4
5
6
7
// 注解表示这是一个 mybatis 的 mapper 类
// 注解表示这是一个 dao 层的类
public interface UserMapper {
List<Student> queryStudentList();
}Controller:StudentController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StudentController {
private UserMapper userMapper;
public List<Student> query() {
List<Student> students = userMapper.queryStudentList();
for (Student student : students) {
System.out.println(student);
}
return students;
}
}
Shiro
Apache Shiro 是 Java 的一个安全框架。Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境。Shiro 可以帮助我们完成:认证、授权、加密、会话管理、与 Web 集成、缓存等。这不就是我们想要的嘛,而且 Shiro 的 API 也是非常简单;
导入 maven 依赖
编写 shiro.ini 配置文件
SQL 使用对象传递参数
返回 response
1 |
|
- Post title:java
- Post author:auggie
- Create time:2022-05-14 21:48:23
- Post link:https://ruanjiancheng.github.io/2022/05/14/java/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.