目录
前言
继续接着后端的学习,本篇博客我们主要设计Tomcat以及Servlet的部署,还有Servlet的使用方法!!!
Tomcat
Tomcat是一个HTTP服务器
Tomcat的部署
1、选择Tomcat8即可
2、直接解压缩
3、解压后的文件夹,找到bin目录下的startup.bat,双击点击启动
看到这个信息,就证明启动成功了
4、Tomcat默认端口是8080,当出现这个欢迎页面时,就证明tomcat跑起来了
Tomcat的使用
1、将html代码拷贝至webapps目录下
2、在浏览器输入127.0.0.1:8080/代码名称
Servlet
Servlet是一种实现动态页面的技术,是一组Tomcat提供给程序员的API,用来构建动态页面这个任务
第一个servlet程序
1、创建项目
创建一个maven项目
项目创建好了之后的目录结构
2、引入servlet依赖
maven的一个核心功能,就是能够自动的管理依赖,就会把咱们使用的库里依赖的东西,自动从中央仓库上,下载下来
选择3.1.0版本
选择maven,把maven里的代码复制下来,粘贴到pom.xml中
3、创建目录结构
创建webapp目录
在webapp目录下,创建一个WEB-INF目录,并创建一个web.xml文件
将这段代码放入web.xml中
4、编写代码
在java目录下创建package
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 krystal
* @date 2022/12/1 10:36
*/
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//是tomcat这边打印个日志
System.out.println("hello");
//还可以给客户端返回个hello
resp.getWriter().write("hello");
}
}
此时doGet所做的工作,就是“根据请求计算响应”,req对象,这是Tomcat把HTTP请求报文,解释成一个对象了,resp对象,则是Tomcat构造的一个空的对象(resp相当于一个“输出型参数”)
doGet就需要根据req里的一些数据+业务逻辑构造生成一个完整的resp对象,在进一步,tomcat就把resp对象转成一个HTTP响应报文
5、打包程序
使用maven进行打包,打开maven窗口双击package
打包成功
成功后,我们可以在target目录下,生成一个jar包
tomcat要求的压缩包格式,是war包,这就需要我们修改pom.xml,添加以下代码
6、部署程序
把war包拷贝到tomcat的webapps中
重新启动tomcat
7、验证程序
通过浏览器,构造一个HTTP请求,来访问Tomcat服务器
Smart Tomcat
以上步骤可以简化操作,“一键式”打包和部署,可以使用第三方的Smart Tomcat插件来完成
配置smart tomcat插件
这里需要手动配置Context Path
tomcat的运行方式:
1、直接在startup这里运行,手动拷贝war包过去;
2、直接通过java代码,调用tomcat的jar包运行,则不需要调用的时候指定tomcat加载哪个webapp(只能加载一个)(smart tomcat的方式)
访问出错
404
1、路径写错了;
2、webapp没有被tomcat正确加载
错误实例1:少写了Context Path
错误实例2:少写了Servlet Path
错误实例3:Servlet Path和URL不匹配
错误实例4:web.xml写错了
405
对应的HTTP请求方法没有实现
还有一种情况:忘记删除super.do代码
500
服务器代码抛异常
出现“空白页面”
响应数据的操作可能没有执行到
出现“无法访问此网站”
tomcat没有启动或者ip/端口写错了
Servlet API
HttpServlet
核心方法
方法名称 | 调用时机 |
init
|
在
HttpServlet
实例化之后被调用一次
|
destroy
|
在
HttpServlet
实例不再使用的时候调用一次
|
service
|
收到
HTTP
请求的时候调用
|
doGet
|
收到
GET
请求的时候调用
(
由
service
方法调用
)
|
doPost
|
收到
POST
请求的时候调用
(
由
service
方法调用
)
|
doPut/doDelete/doOptions/...
|
收到其他请求的时候调用
(
由
service
方法调用
)
|
Servlet的生命周期
初始阶段,实例化的时候,调用一次init
结束销毁之前,调用一次destroy
每次收到请求,调用service
HttpServletRequest
核心方法
方法名称 | 调用时机 |
String getProtocol()
|
返回请求协议的名称和版本。
|
String getMethod()
|
返回请求的
HTTP
方法的名称,例如,
GET
、
POST
或
PUT
。
|
String getRequestURI()
|
从协议名称直到
HTTP
请求的第一行的查询字符串中,返回该请求的 URL
的一部分。
|
String getContextPath()
|
返回指示请求上下文的请求
URI
部分。
|
String getQueryString()
|
返回包含在路径后的请求
URL
中的查询字符串。
|
Enumeration
getParameterNames()
|
返回一个
String
对象的枚举,包含在该请求中包含的参数的名称。
|
String getParameter(String
name)
|
以字符串形式返回请求参数的值,或者如果参数不存在则返回null。
|
String[]
getParameterValues(String
name)
|
返回一个字符串对象的数组,包含所有给定的请求参数的值, 如果参数不存在则返回 null
。
|
Enumeration
getHeaderNames()
|
返回一个枚举,包含在该请求中包含的所有的头名。
|
String getHeader(String
name)
|
以字符串形式返回指定的请求头的值。
|
String
getCharacterEncoding()
|
返回请求主体中使用的字符编码的名称。
|
String getContentType()
|
返回请求主体的
MIME
类型,如果不知道类型则返回
null
。
|
int getContentLength()
|
以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1
。
|
InputStream
getInputStream()
|
用于读取请求的
body
内容
.
返回一个
InputStream
对象
.
|
打印请求信息
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 krystal
* @date 2022/12/1 15:30
*/
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
StringBuilder stringBuilder=new StringBuilder();
stringBuilder.append(req.getProtocol());
stringBuilder.append("\n");
stringBuilder.append(req.getMethod());
stringBuilder.append("\n");
stringBuilder.append(req.getRequestURI());
stringBuilder.append("\n");
stringBuilder.append(req.getContextPath());
stringBuilder.append("\n");
stringBuilder.append(req.getQueryString());
stringBuilder.append("\n");
//把请求的header也拼进来
Enumeration<String> headNames=req.getHeaderNames();
while (headNames.hasMoreElements()){
String name=headNames.nextElement();
String value=req.getHeader(name);
stringBuilder.append(name+":"+value);
stringBuilder.append("\n");
}
resp.getWriter().write(stringBuilder.toString());
//System.out.println(stringBuilder.toString());
}
}
获取GET请求中的参数
GET请求中的参数一般都是通过query string传递给服务器的,在服务器端就可以通过getParameter来获取到参数的值
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 krystal
* @date 2022/12/1 16:15
*/
@WebServlet("/getParameter")
public class GetParameterServlet extends HelloServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取 query string 中的键值对.
// 假设浏览器的请求形如 ?studentId=10&studentName=张三
String studentId = req.getParameter("studentId");
String studentName = req.getParameter("studentName");
System.out.println(studentId);
System.out.println(studentName);
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write(studentId + ", " + studentName);
}
}
获取post请求中body中的参数
1、请求的body是x-www-form-urlencoded,使用getParameter来获取的
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过body获取,发个post请求
String studentId = req.getParameter("studentId");
String studentName = req.getParameter("studentName");
System.out.println(studentId);
System.out.println(studentName);
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write(studentId + ", " + studentName);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="getParameter" method="post">
<input type="text" name="studentId">
<input type="text" name="studentName">
<input type="submit" value="提交">
</form>
</body>
</html>
还可以使用postman构造这种请求
2、请求的body是json
import com.fasterxml.jackson.databind.ObjectMapper;
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 krystal
* @date 2022/12/1 17:35
*/
class Student{
//1、这个类里的属性必须是public或者带有public的getter和setter
// 否则,jackson无法访问这个对象的属性
//2、这个类务必要有无参版本的构造方法,如果不写任何构造方法,编译器能自动生成无参构造
public int studentId;
public String studentName;
}
@WebServlet("/json")
public class JsonServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//jackson提供的核心的类
//一个方法为readValue,把json格式的数据转成java对象
//一个方法为writeValueAsString,把json对象转成json格式的字符串
ObjectMapper objectMapper=new ObjectMapper();
//readValue第一个参数可以是字符串,也可以时输入流
//第二个参数,是一个类对象,也就是要解析出来的结果的对象的类
Student s=objectMapper.readValue(req.getInputStream(),Student.class);
System.out.println(s.studentId);
System.out.println(s.studentName);
// resp.setContentType("text/html;charset=utf8");
// resp.getWriter().write(s.studentId+","+s.studentName);
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(objectMapper.writeValueAsString(s));
}
}
HttpServletResponse
核心方法
方法 | 描述 |
void setStatus(int sc)
|
为该响应设置状态码
|
void setHeader(String name,
String value)
|
设置一个带有给定的名称和值的
header.
如果
name
已经存在
,
则覆盖旧的值
|
void addHeader(String
name, String value)
|
添加一个带有给定的名称和值的
header.
如果
name
已经存在
,
不覆盖旧的值
,
并列添加新的键值对
|
void setContentType(String
type)
|
设置被发送到客户端的响应的内容类型。
|
void
setCharacterEncoding(String
charset)
|
设置被发送到客户端的响应的字符编码(
MIME
字符集)例
如,
UTF-8
。
|
void sendRedirect(String
location)
|
使用指定的重定向位置
URL
发送临时重定向响应到客户端。
|
PrintWriter getWriter()
|
用于往
body
中写入文本格式数据
.
|
OutputStream
getOutputStream()
|
用于往
body
中写入二进制格式数据
.
|
设置状态码
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 krystal
* @date 2022/12/1 19:04
*/
@WebServlet("/status")
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//约定,浏览器query string传个参数过来
String type=req.getParameter("type");
if (type.equals("1")){
resp.setStatus(200);
}else if (type.equals("2")){
resp.setStatus(404);
//返回tomcat自带的错误页面
resp.sendError(404);
}else if (type.equals("3")){
resp.setStatus(500);
}else {
resp.setStatus(504);
}
}
}
自动刷新
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 krystal
* @date 2022/12/1 19:22
*/
@WebServlet("/autoRefresh")
public class AutoRefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//直接返回响应就好
resp.setHeader("refresh","2");
resp.getWriter().write(System.currentTimeMillis()+"");
}
}
构造一个重定向响应
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 krystal
* @date 2022/12/1 19:41
*/
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(302);
resp.setHeader("Location","https://www.sogou.com");
}
}
表白墙
需要让用户留言的数据能够在服务器这边保存,就可以保证页面关闭,数据不会丢失
1、创建项目,引入依赖,创建目录结构
2、设计前后端如何交互(什么时候发请求,发的请求什么样,返回的响应什么样)
/**
* @author krystal
* @date 2022/12/1 22:46
*/
public class Message {
private String from;
private String to;
private String message;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
/**
* @author krystal
* @date 2022/12/2 9:17
*/
public class DBUtil {
private static volatile DataSource dataSource=null;
public static DataSource getDataSource(){
if (dataSource==null){
synchronized (DBUtil.class){
if (dataSource==null){
dataSource=new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/bb?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("19930112");
}
}
}
return dataSource;
}
private DBUtil(){
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
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 javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* @author krystal
* @date 2022/12/1 19:57
*/
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
private ObjectMapper objectMapper=new ObjectMapper();
//负责让页面获取到数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf8");
List<Message> messageList= null;
try {
messageList = load();
} catch (SQLException e) {
e.printStackTrace();
}
resp.getWriter().write(objectMapper.writeValueAsString(messageList));
}
//提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取body中的数据并解析
Message message=objectMapper.readValue(req.getInputStream(),Message.class);
//将数据保存在内存中
//messageList.add(message);
try {
save(message);
} catch (SQLException e) {
e.printStackTrace();
}
resp.setStatus(200);
System.out.println("提交数据成功!from="+message.getFrom()+",to="+message.getTo()+",message="+message.getMessage());
}
private List<Message> load() throws SQLException {
//从数据库查询数据
//1、先有一个数据源
DataSource dataSource=DBUtil.getDataSource();
//2、建立连接
Connection connection=dataSource.getConnection();
//3、构造sql语句
String sql="select * from message";
PreparedStatement statement=connection.prepareStatement(sql);
//4、执行sql
ResultSet resultSet =statement.executeQuery();
//5、遍历结果集合
List<Message> messageList=new ArrayList<>();
while (resultSet.next()){
Message message=new Message();
message.setFrom(resultSet.getString("from"));
message.setTo(resultSet.getString("to"));
message.setMessage(resultSet.getString("message"));
messageList.add(message);
}
//5、关闭连接
statement.close();
connection.close();
return messageList;
}
private void save(Message message) throws SQLException {
//保存数据
//1、先有一个数据源
DataSource dataSource=DBUtil.getDataSource();
//2、建立连接
Connection connection=dataSource.getConnection();
//3、构造sql语句
String sql="insert into message values(?,?,?)";
PreparedStatement statement=connection.prepareStatement(sql);
statement.setString(1,message.getFrom());
statement.setString(2,message.getTo());
statement.setString(3,message.getMessage());
//4、执行sql
int ret=statement.executeUpdate();
System.out.println("ret="+ret);
//5、关闭连接
statement.close();
connection.close();
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>表白墙</title>
</head>
<body>
<style>
.container{
width: 400px;
margin: 0 auto;
}
h1{
text-align: center;
}
p{
text-align: center;
color: #666;
}
.row{
height: 40px;
display: flex;
/* 水平居中 */
justify-content: center;
/* 垂直居中 */
align-items: center;
}
.row span{
width: 100px;
}
.row input{
width: 200px;
height: 20px;
}
.row button{
width: 310px;
height: 30px;
color: white;
background-color: orange;
border: none;
}
.row button:active{
background-color: #666;
}
</style>
<div class="container">
<h1>表白墙</h1>
<p>输入后点击提交,就会把信息显示在表格中</p>
<div class="row">
<span>谁:</span><input type="text">
</div>
<div class="row">
<span>对谁:</span><input type="text">
</div>
<div class="row">
<span>说什么:</span><input type="text">
</div>
<div class="row">
<button>提交</button>
</div>
</div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
let container=document.querySelector('.container');
let button=document.querySelector('button');
button.onclick=function(){
//1.获取到输入框的内容
let inputs=document.querySelectorAll('input');
let from=inputs[0].value;
let to=inputs[1].value;
let message=inputs[2].value;
if(from=='' || to=='' || message==''){
alert('输入的内容为空');
return;
}
console.log(from+','+to+','+message);
//2.能够构造出新的div,用来保存用户提交的内容
let rowDiv=document.createElement('div');
rowDiv.className='row';
rowDiv.innerHTML=from+"对"+to+"说:"+message;
container.appendChild(rowDiv);
//3.提交完后,清空输入框的内容
for(let i=0;i<inputs.length;i++){
inputs[i].value='';
}
let data={
from:from,
to:to,
message:message
};
//4、点击发送按钮,给服务器发送个post请求
$.ajax({
type:'post',
url:'message',
//这里放的是body的内容
data:JSON.stringify(data),
contentType:"application/json;charset=utf8",
success:function(body){
console.log("提交数据成功");
}
});
}
// 直接写在 script 标签里的代码, 都是在页面加载的时候执行的.
// 来获取服务器的数据
function getMessage(){
$.ajax({
type:"get",
url:"message",
success:function(body){
// body 就是响应的 body 内容, json 数组.
// jquery 非常智能的帮我们把 json 数组给解析成了 js 对象数组
// 但是有个前提条件, 就是响应的 Content-Type 得是 application/json
for(let i=0;i<body.length;i++){
let message=body[i];
let row=document.createElement('div');
row.className='row';
row.innerHTML=message.from+"对"+message.to+"说"+message.message;
container.appendChild(row);
}
}
});
}
getMessage();
</script>
</body>
</html>