静态资源是已经写好的,动态资源是即时更新的
html,css,js一般主要用作静态资源
对于动态资源:现在开发一般都是前后端分离,前端需要调用后端的结果,因为数据往往是存到数据库中,前端展示的数据是来自于数据库中的,即数据不是写死的
ps:一般前后端通过json串来互相解析
首先明确,Servlet是一个接口
Servlet的生命周期
分为5个阶段:加载、创建、初始化、处理客户请求、卸载。
(1)加载:容器通过类加载器使用servlet类对应的文件加载servlet
(2)创建:通过调用servlet构造函数创建一个servlet对象
(3)初始化:调用init方法初始化
(4)处理客户请求:每当有一个客户请求,容器会创建一个线程来处理客户请求
(5)卸载:调用destroy方法让servlet自己释放其占用的资源
三个主要方法
初始化——init(懒汉模式创建的单例对象,初始化时自动调用且只调用一次)
处理请求响应阶段——service(req,resp)(处理一次调用一次)
销毁阶段——destroy(只销毁一次)
首先明确,Servlet是一个接口,HttpServlet是一个实现这个接口的抽象类,所以我们实现时,可以自定义类,继承这个抽象类,通过覆写doGet,doPost方法对HttpRequest,HttpResponse进行获取和设定,来达到通信
模板步骤如下:
引入Servlet依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
继承HtttpServlet实现自己的类
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author sunny
* @date 2022/06/15 10:07
**/
@WebServlet("/Model")
//通过该注解将url地址/first和这个资源进行绑定,我输入/first就可以请求到这个资源
public class HttpServletModel extends HttpServlet {
// 重写这个类,表明我们这个类支持Get请求访问
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Your code
// 通过参数req,获取http请求
// 通过参数resp设置响应内容
}
// 重写这个类,表明我们这个类支持Get请求访问
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// code
}
}
语法格式:
(1)注解
(2)响应体
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/plain");
PrintWriter writer = resp.getWriter();
writer.println("hello");
writer.println("world");
}
(3)读取请求参数
无论是Get请求,还是Post请求,我们都采用相同的方法读取
但要注意:
GET方法:提交的参数中英文都可正常读取,读取到的内容附在url后,即放在 queryString中:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**获取用户输入的数据(GET方法提交)
* @author sunny
* @date 2022/06/10 21:36
**/
@WebServlet("/get")
public class GetParameter extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表单提交</title>
</head>
<body>
<form method="get" action="/get">
<input type="text" name="username">
<input type="password" name="password">
<button>提交</button>
</form>
</body>
</html>
点击提交:
POST方法:必须req.setCharacterEncoding(“utf-8”)设置编码才可正常读取中文
以form表单提交,则参数默认是带在请求体中的,并不在url中体现
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**获取用户输入的数据(GET方法提交)
* @author sunny
* @date 2022/06/10 21:36
**/
@WebServlet("/post")
public class GetParameter extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// post方法一定要设置字符集编码
req.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表单提交</title>
</head>
<body>
<form method="post" action="/post">
<input type="text" name="username">
<input type="password" name="password">
<button>提交</button>
</form>
</body>
</html>
点击提交:
当然,Post也可以带在url中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表单提交</title>
</head>
<body>
<!--以query string的形式post提交,不过这个例子这样写则无论用户的username输入什么,得到的都是aaa-->
<form method="post" action="/post?username=aaa">
<input type="text">
<input type="text" name="password">
<button>提交</button>
</form>
</body>
</html>
(1)请求行与请求头们
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
/**
* @author sunny
* @date 2022/06/06 21:01
**/
@WebServlet("/second")
public class Second extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 请求行信息
String method = req.getMethod();
System.out.println("HTTP 方法: " + method);
System.out.println();
System.out.println();
String requestURI = req.getRequestURI();
System.out.println("requestURI: " + requestURI);
StringBuffer requestURL = req.getRequestURL();
System.out.println("requestURL: " + requestURL.toString());
String pathInfo = req.getPathInfo();
System.out.println("pathInfo: " + pathInfo);
String contextPath = req.getContextPath();
System.out.println("contextPath: " + contextPath);
String servletPath = req.getServletPath();
System.out.println("servletPath: " + servletPath);
String pathTranslated = req.getPathTranslated();
System.out.println("pathTranslated: " + pathTranslated);
System.out.println();
System.out.println();
String serverName = req.getServerName();
System.out.println("serverName: " + serverName);
int serverPort = req.getServerPort();
System.out.println("serverPort: " + serverPort);
String scheme = req.getScheme();
System.out.println("schema: " + scheme);
String protocol = req.getProtocol();
System.out.println("protocol: " + protocol);
System.out.println();
System.out.println();
// 请求头们
Enumeration<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()){
String name = headerNames.nextElement();
String value = req.getHeader(name);
System.out.println("name:" + name + " value:" + value);
}
}
}
(2)请求体
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
@WebServlet("/req-body")
public class ReqBodyServlet extends HttpServlet {
// 重写了 doPost 方法,所以我们这个资源支持了 POST 方法,但不支持 GET 请求
// 不能直接在浏览器里直接输入这个 URL 回车,会看到 405 的
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 方法一
InputStream inputStream = req.getInputStream();
byte[] buf = new byte[1024];
int n = inputStream.read(buf);
// byte[] -> String 字符集解码
String reqBody = new String(buf, 0, n, "UTF-8");
System.out.println(reqBody);
// 方法二
// BufferedReader reader = req.getReader();
// char[] buf = new char[1024];
// int n = reader.read(buf); // n 单位是字符
// String reqBody = new String(buf, 0, n);
// System.out.println(reqBody);
}
}
【其实实际应用中,只需获取请求参数,用getParameter即可,上面这两种方法是把请求体全部获取到,了解即可】
其实用1.4中的响应模板即可,这里看看就行:
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
@WebServlet("/set-resp")
public class SetRespServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置响应状态
// resp.setStatus(204);
// 设置响应头(header)
// 响应头的 Name
// 1. 标准响应头,比如 Content-Type(PS:Content-Length 不需要我们设置)
// 2. 非标准响应头,填什么都可以(中文不行)
// 3. Name 不区分大小写
// resp.setHeader("Content-Type", "text/plain; charset=gbk");
// resp.setHeader("X-My-Class", "Java19");
// 响应体的内容是字符(使用较多的)
// resp.setCharacterEncoding("utf-8");
// resp.setContentType("text/plain");
// PrintWriter writer = resp.getWriter(); // 设置响应字符集要在 getWriter() 之前
//
// writer.print("你好");
// 响应体的内容是字节流
OutputStream outputStream = resp.getOutputStream();
outputStream.write('H');
outputStream.write('e');
}
}
语义不同,GET代表获取,POST代表提交
GET不应该带有请求体,POST可以带有请求体
对于请求参数,GET方法的参数放在 query string中,POST方法(form表单提交)方法的参数可以直接放在 query string中也可以放在request body中
POST比GET稍微安全一点,因为URL一般会记录在日志中,请求体不会记录日志
【HTTP方法的幂等性是指一次和多次请求某一个资源应该具有同样的副作用】
CGI(Common Gateway Interface)——通用网关接口, 传统技术中,动态的网页建立和显示都是通过CGI来实现
对于每个请求,都要产生一个新的进程进行处理。因为每个进程都会占有很多服务器的资源和时间,这就导致服务器无法同时处理很多的并发请求, 特别是访问量高的时候),就要消耗系统越多的处理时间,只剩下越来越少的系统资源,对于用户来说,只能是漫长的等待服务器端的返回页面了 。 并且无法克服CGI程序与数据库建立连接时速度慢的瓶颈,从而死机、数据库死锁现象频繁发生
另外CGI程序都是与操作系统平台相关的,虽然在互联网爆发的初期,CGI为开发互联网应用做出了很大的贡献,但是随着技术的发展,开始逐渐衰落
Servlet充分发挥了服务器端的资源并高效的利用。 Servlet对每个请求都是单独启动一个线程,而不是进程。这种处理方式大幅度地降低了系统里的进程数量,提高了系统的并发处理能力, 我们的Servlet有连接池的概念,它可以利用多线程的优点,在系统缓存中事先建立好若干与数据库的连接,到时候若想和数据库打交道可以随时跟系统"要"一个连接即可,反应速度可想而知。
另外因为Java Servlet是运行在虚拟机之上的,也就解决了跨平台问题 。 Servlet具备Java的平台无关性,在系统开发过程中保持了系统的可扩展性、高效性。
JSP???
在Servlet出现之后,随着使用范围的扩大,人们发现了它的一个很大的一个弊端。那就是 为了能够输出HTML格式内容,需要编写大量重复代码,造成不必要的重复劳动。
为了解决这个问题,基于Servlet技术产生了JavaServet Pages技术,也就是JSP。Servlet和JSP两者分工协作,Servlet侧重于解决运算和业务逻辑问题,JSP则侧重于解决展示问题。 Servlet与JSP一起为Web应用开发带来了巨大的贡献,后来出现的众多Java Web应用开发框架都是基于这两种技术的,更确切的说,都是基于Servlet技术的。
先来回顾一下url的格式:
protocol——本次资源对应的协议(不一定全部是HTTP协议,所以需要标识一下是哪个协议)
+域名或IP——主机host(资源在哪台主机上)
+端口——资源在这个主机的哪个进程上获取
+资源路径——具体定位到是哪个资源
其中资源路径由两部分组成:Context Path + Servlet Path
(1)到底什么是ajax???
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
我们这里是ajax的应用之一—— 运用 JavaScript 操作 DOM(Document Object Model)来执行动态效果
即之前html中都是通过,等标签间接引导浏览器去发送http请求,而ajax则可以自己发送请求
即我们这里的ajax包含在Javascript中,运用 JavaScript 操作 DOM(Document Object Model)来执行动态效果 ,进而影响用户看到的内容
(2)ajax的简单使用
创建 XMLHttpRequest 对象
如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法:
xmlhttp.open("GET","ajax_info.txt",true);
xmlhttp.send();
如需获得来自服务器的响应,请使用 XMLHttpRequest 对象的 responseText 或 responseXML 属性
如: document.getElementById(“myDiv”).innerHTML=xmlhttp.responseText;
看下面这个请求的小栗子:
// 利用这个对象发起 HTTP 请求
var xhr = new XMLHttpRequest();
xhr.open("get", "/data/students.json");
// 以时间驱动的方式,读取响应 —— 当 xhr 完成响应时,执行我们准备好的函数
xhr.onload = function () {
console.log(this); // this 就是 xhr 对象
console.log(this.responseText); // string 类型
console.log(xhr.responseText); // string 类型
// 我们希望把 json 字符串解析成 js 的具体数据类型
var sts = JSON.parse(this.responseText);
console.log(sts);
}
xhr.send(); // 发送 HTTP 请求
(1)什么是重定向?
重定向——请求某个资源,这个资源又定位到了另一个资源
重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置(如:网页重定向、域名的重定向、路由选择的变化也是对数据报文经由路径的一种重定向)。
(2)重定向方法
新网址完全继承旧网址, 假如当你访问 a.com时 永久重定向到了 b.com ;那么下一次访问 a.com 时浏览器会直接跳转到 b.com 不会再请求a.com
对旧网址没有影响, 假如当你访问 a.com 时 临时重定向到了 b.com ; 那么下一次当你请求 a.com
时浏览器还会先请求 a.com ,然后再重定向到b.com临时重定向时没有考虑是否保留原方法,大部分浏览器都实现成不保留的了,就是都退化成GET请求了,所以有了以下两个优化:307和303
以不保留方法的临时重定向为例:
实际上,一般我们直接用resp带有的sendRedirect();方法即可,这个方法是临时重定向(302)
resp.sendRedirect("重定向的目标资源");
(3) forword VS Redirect
forward,服务器获取跳转页面内容传给用户,用户地址栏不变
redirect(重定向),是服务器向用户发送转向的地址,redirect后地址栏变成新的地址
对于一个项目而言,其实如果项目全程都是一个人搞定,也可以使用模板技术(jsp,thymeleaf),对于模板技术,我们不再过多分析
现在,一般都是前后端分离,下面以前后端分离为重点:
MVC——Model View Controller
前后端数据的交互,一般是听过json串来进行数据交互
ps【】:关于jar包和war包
Jar包是普通的Java程序打包,里面是.class文件
War包则是Java Web程序打包,里面除了有.class文件还有其他诸如html的静态资源,也只有被打包成war包,才会被Tomcat识别
那么,什么是json串呢?
所以,JavaScript中创建json实例,然后通过ajax进行传输
大括号 {} 保存对象
中括号 [] 保存数组,数组可以包含多个对象
JSON 对象在大括号 {} 中书写:
{key1 : value1, key2 : value2, ... keyN : valueN }
JSON 数组在中括号 [] 中书写:
数组可包含多个对象:
[
{ key1 : value1-1 , key2:value1-2 },
{ key1 : value2-1 , key2:value2-2 },
{ key1 : value3-1 , key2:value3-2 },
...
{ key1 : valueN-1 , key2:valueN-2 },
]
通过 JavaScript,您可以创建一个对象数组,并像这样进行赋值:
实例:
var sites = [
{ "name":"runoob" , "url":"www.runoob.com" },
{ "name":"google" , "url":"www.google.com" },
{ "name":"微博" , "url":"www.weibo.com" }
];
//可以像这样访问 JavaScript 对象数组中的第一项(索引从 0 开始):
sites[0].name;
返回的内容是:
runoob
在向服务器发送数据时一般是字符串。,即前端向服务器发送数据,要将前端JS中的数据对象序列化为字符串
我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符串。
实例:
var obj = { "name":"runoob", "alexa":10000,
"site":"www.runoob.com"};
var myJSON = JSON.stringify(obj);
document.getElementById("demo").innerHTML = myJSON;
我们可以使用 JSON.parse() 方法将数据转换为 JavaScript 对象。
XMLHttpRequest.responseText是全部后端的返回数据
// 进行 JSON 的反序列
var students = JSON.parse(this.responseText);
得到反序列化对象students后,就可以将该对象按我们想要的格式渲染进html中;
var tbody = document.querySelector('tbody');
for (var i in students) {
var s = students[i];
var tr = `<tr><td>${s.姓名}</td><td>${s.成绩}</td></tr>`;
tbody.innerHTML = tbody.innerHTML + tr;
}
如果我们自己按照json格式,把对象变成json格式的字符串是很麻烦的,如下:
// private String getJSON1() {
// StringBuilder sb = new StringBuilder();
// sb.append("[");
// for (Map.Entry<String, Integer> entry : gradeMap.entrySet()) {
// String name = entry.getKey();
// int value = entry.getValue();
// sb.append("{")
// .append("\"姓名\": ")
// .append("\"")
// .append(name)
// .append("\",")
// .append("\"成绩\": ")
// .append(value)
// .append("},");
// }
// sb.delete(sb.length() - 1, sb.length());
// sb.append("]");
//
// return sb.toString();
// }
所以,有别人已经实现这个功能了,我们直接借用即可:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
ObjectMapper om = new ObjectMapper();
om.writerWithDefaultPrettyPrinter().writeValueAsString(list);
源码链接:
https://gitee.com/serendi-pity/grade_web_separation
本地存储:D:\JIDEA_code\grade_web_separation
大体目录结构:
实现内容:
如:输入bb 14,点击提交
返回成绩列表:
从业务流程角度看逻辑:
所以: