全文来自于https://itbaima.net/document和 韩顺平的笔记
新版tomcat
1. 配置
tomcat的服务器响应流程
请添加图片描述
Servlet的生命周期,Servlet是个接口
- Servlet的实现
public class TestServlet implements Servlet {
public TestServlet(){
System.out.println("我是构造方法!");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("我是init");
}
@Override
public ServletConfig getServletConfig() {
System.out.println("我是getServletConfig");
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("我是service");
}
@Override
public String getServletInfo() {
System.out.println("我是getServletInfo");
return null;
}
@Override
public void destroy() {
System.out.println("我是destroy");
}
}
- 生命周期的流程
只有调用这个servlet 生命周期才开始
也就是说只有访问了servlet映射的url 这个servlet才会开始init方法
- 首先执行构造方法完成 Servlet 初始化
- Servlet 初始化后调用 init () 方法。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 销毁前调用 destroy() 方法。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
HttpServlet,这个是Servlet的抽象类
类似于servlet的化简版
它已经帮助我们提前实现了一些操作,这样就会给我们省去很多的时间。
我们只要关注request和response就行。
差不多长这样
public class TestS2 extends HttpServlet {
@Override
public void init() throws ServletException {
System.out.println("init S2");
super.init();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("<h1>恭喜你解锁了全新玩法</h1>"); }
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
通过注解配置Servlet
@WebServlet({"/test3","/lala.html","*.do"})
public class TestS3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8"); //设置响应内容类型
resp.getWriter().write("lalala");
}
}
tomcat 整合 mybatis
- servlet写法
@WebServlet("/reg")
public class TestS5 extends HttpServlet {
private SqlSessionFactory sqlSessionFactory;
@Override
public void init() throws ServletException {
URL resource = this.getClass().getClassLoader().getResource("mybatis-config.xml");
String path = resource.getPath();
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(new FileInputStream(path));
System.out.println("sqlSessionFactory = " + sqlSessionFactory);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
super.init();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
//获取POST请求携带的表单数据
Map<String, String[]> map = req.getParameterMap();
//判断表单是否完整
map.forEach((k,v)->{
System.out.println(k+" "+ Arrays.toString(v));
});
var username = req.getParameter("username");
var password = req.getParameter("password");
var email = req.getParameter("email");
SqlSession sqlSession = sqlSessionFactory.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.add(new User().setUsername(username).setPassword(password).setEmail(email));
resp.getWriter().write("注册成功!");
}
}
- mybatis配置
public interface UserMapper {
@Insert("insert into users(username,password,email) values(#{user.username},#{user.password},#{user.email})")
void add( @Param("user") User user);
@Select("select * from users where username=#{username} and password=#{password}")
User selectUserByNameAndPwd(@Param("username") String username, @Param("password") String password);
}
文件下载
- 后端
- mavne引入commons-io
- mybatis 的 Resources.getResourceAsStream()方法可以读取Resource下的文件
- commons-io 的 IOUtils.copy()方法可以快速拷贝io
- resp.setContentType(“image/jpeg”);告诉浏览器我要返回图片
@WebServlet("/file")
public class TestS6 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 这两步已经告诉浏览器,我要返回图片 而且下面那个IOUtils.copy()方法会自动把图片写入resp的输出流
resp.setContentType("image/jpeg");
OutputStream outputStream = resp.getOutputStream();
// Resources是mybatis提供的工具类,快速读取io
URL resource = this.getClass().getClassLoader().getResource("5.jpg");
String path = resource.getPath();
System.out.println("path = " + path);
// 这个是直接读Resource下的文件 牛逼啊
InputStream resourceAsStream = Resources.getResourceAsStream("5.jpg");
// InputStream inputStream =new FileInputStream(path);
// IOUtils是commons-io提供的,快速拷贝io
IOUtils.copy(resourceAsStream, outputStream);
}
}
- 前端
- a标签的download属性可以指定下载的文件名
<a href="file" download="5.jpg">点我下载高清资源</a>
文件上传
- servlet
- 需要加上@MultipartConfig注解
- maven引入commons-io
- maven引入
commons-fileupload
(这个我这里没用 但是确实是可以用)
@MultipartConfig //标记这个Servlet支持文件上传
@WebServlet("/file2")
public class TestS7 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 他这个好像是没法拿名字 我要去找一下笔记
try(FileOutputStream stream = new FileOutputStream("C:\\Users\\23584\\Desktop\\IDEAUtf-8\\new\\webT\\src\\main\\resources\\img3.png")){
Part part = req.getPart("test-file");//前端的name属性
IOUtils.copy(part.getInputStream(), stream);
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write("文件上传成功!");
}
}
}
- 前端
- form表单需要加上
enctype="multipart/form-data"
- input需要加上
type="file"
- input需要加上
name="test-file"
,这个name属性是后端拿到文件的key - 如果想一次性上传多个文件,可以在input标签中加上
multiple
属性
<form action="file2" method="post" enctype="multipart/form-data">
<input type="file" name="test-file">
<input type="submit" value="上传">
</form>
初始化参数
当前servlet的初始化参数
@WebServlet(value = "/test9", initParams = {
@WebInitParam(name = "name", value = "karl"),
})
public class TestS9 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(getInitParameter("name"));
ServletContext context = getServletContext();
System.out.println(context.getInitParameter("lbwnb"));
}
}
全局初始化参数
直接在web.xml
里和servlet同级别
的位置加上
<context-param>
<param-name>lbwnb</param-name>
<param-value>lbwnb</param-value>
</context-param>
重定向和请求转发
重定向(Redirect)
用途:
- 在完成POST请求后进行重定向,以防止表单的重复提交(POST/Redirect/GET模式)。
- 在页面或资源被移动到新的URL时通知客户端。
请求转发(Forward)
用途:
- 在不想暴露服务器内部结构的情况下,将请求委托给其他处理程序。
- 当需要在多个组件之间共享请求数据时。
比较
特性 | 重定向 | 请求转发 |
---|---|---|
跳转方式 | 客户端跳转 | 服务器端跳转 |
URL变化 | 地址栏显示新的URL | 地址栏URL不变 |
HTTP状态码 | 301, 302, 303, 307等 | 通常是200 OK |
数据传递 | 数据不会自动传递到新的URL | 请求数据在转发中被保留并可用 |
请求/响应周期 | 会启动新的请求/响应周期 | 在同一个请求/响应周期内完成 |
可见性 | 对客户端可见 | 对客户端不可见 |
性能 | 消耗更多资源,因为涉及到两次请求/响应 | 相对节省资源,因为只有一次处理流程 |
举例来说,在Java的Servlet中,重定向和请求转发的实现如下:
重定向的Java Servlet实现:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ... 其他处理逻辑 ...
response.sendRedirect("http://www.example.com/newpage");
}
请求转发的Java Servlet实现:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ... 其他处理逻辑 ...
RequestDispatcher dispatcher = request.getRequestDispatcher("/newpage");
dispatcher.forward(request, response);
}
Ajax(前后端以后直接用axios了)
- 前端
<body>
<hr>
<div id="time"></div>
<br>
<button onclick="updateTime()">更新数据</button>
</body>
<script>
function updateTime() {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
document.getElementById("time").innerText = xhr.responseText
}
};
xhr.open('GET', 'time', true);
xhr.send();
}
</script>
- 后端
@WebServlet("/time")
public class TestS8 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String date = dateFormat.format(new Date());
resp.setContentType("text/html;charset=UTF-8");
resp.getWriter().write(date);
}
}
ServletContext
ServletContext的简介
-
ServletContext 接口:这是一个用于描述Servlet上下文的接口。Servlet上下文是一个为整个web应用提供信息的对象,它允许servlet之间共享数据。
-
唯一性:在一个web应用中,只存在一个
ServletContext
实例。这意味着在该应用中的所有Servlet都共享同一个ServletContext
,这有助于在不同的Servlet之间共享信息。 -
生命周期:
ServletContext
对象在web应用启动时被创建,在应用停止时销毁。这个生命周期与web应用的生命周期是一致的。 -
获取方式:可以通过
ServletConfig.getServletContext()
方法获取ServletContext
对象的引用,或者在Servlet中使用this.getServletContext()
。这提供了一种在Servlet内部访问应用级信息的方式。 -
数据共享:由于所有的Servlet共享同一个
ServletContext
,因此它可以用来在不同的Servlet之间共享数据。这使得ServletContext
成为一个在整个应用范围内共享信息的有用工具。 -
获取web.xml中的配置:可以通过
ServletContext
获取在web.xml
文件中配置的上下文参数(context-param
)。这些参数通常包含了整个web应用的配置信息,而不是特定于某个Servlet的。 -
获取工程路径:
ServletContext
提供了方法来获取当前web应用的上下文路径,这通常是web应用的根路径。 -
获取绝对路径:还可以用它来获取web应用在服务器硬盘上的绝对路径。这在处理文件上传、下载等需要访问服务器文件系统的操作时非常有用。
-
存取数据:
ServletContext
像一个Map一样,可以用来存储和检索数据。由于它是由整个应用共享的,因此可以用来在不同的Servlet之间共享数据。
代码举例
第一部分:设置数据到 ServletContext
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class SetContextServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取ServletContext对象
ServletContext context = this.getServletContext();
// 设置属性
context.setAttribute("data", "这是在ServletContext中设置的数据");
// 响应输出
response.getWriter().println("数据已设置到ServletContext");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
第二部分:从 ServletContext
读取数据
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class GetContextServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取ServletContext对象
ServletContext context = this.getServletContext();
// 从ServletContext获取数据
String data = (String) context.getAttribute("data");
// 响应输出
response.getWriter().println("从ServletContext获取的数据是: " + data);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}