目录
6.理清我们有多少资源,资源支持方法是什么,资源的Path是什么,资源的职责是什么,资源的关系
1.Servlet的日常开发
1.@WebServlet(...此处填写资源路径)
必须以 / 开头,并且路径不能重复
正常情况"/hello" "/hello/world"
特殊情况:
(1)通配符"*.do"只要路径后缀名是 .do的都归我管
这是随便写的路径,路径结尾是.do,所以控制台打印了。
(2)"/" 所有的URL都归它管
随便写的任何路径都可以访问到,包括.do
有了这个再也不会出现404了
(3)" ",一个空格,这代表根目录URL
1.那么什么时候Tomcat会启动失败?
(1)端口被占用
(2)动态资源的绑定路径有错误的情况
2.响应体是文本内容&&字符集编码是uft-8
1.设置字符集编码
2.设置Content-Type的响应头
3.写响应体
不用调用setHeader(...),直接使用以下代码:
3.读取请求参数
——读取网页中收集用户填写的信息
GET方法的参数放在query string中
POST方法的参数放在query string和request body中(备注:必须form提交的POST请求)
当GET请求时
1.请求参数放在URL中,格式是name = value&name=value
2.value是中文还是英文均可以在正常读取
3.如果只有name,没有value,读到的是一个空字符串
4.如果连Name都没有,读到的是null
当POST请求时
1.请求参数可以放在URL的query string中,也可以requery body中(必须提交form表单)
格式都是name=value&name=value
2.value是英文没问题,中文有问题,所以需要读取之前,设置请求的字符集编码(req.setCharacterEncording)
3.如果连name都没有,没有value,读到的是一个空的字符""
4.如果连name都没有,读到的是Null
所以,标准读取参数代码如下:
4.资源的重定向(redirect)
3XX + 响应头:Location
临时重定向有3个状态:
302Found 临时移动,未考虑保留
303See Other 不保留,退化成GET
307Temporary Redirect 保留原方法
302约等于307
2.面试问题:GET和POST有什么区别?
根本区别只有一个,就是语义不同。GET代表获取的语义,POST代表的是提交语义。
具体表现上的不同:
1.标准中规定:GET不应该带有请求体;POST可以带有请求体。
2.有请求参数的话,GET请求放在查询字符串URL中,POST请求放在查询字符串或请求体中(form表单)
由于浏览器的实现,URL的长度限制(1000个字符)短于请求体的限制(无限制)
URL一般会记录在日志中,请求体不会记录日志,所以说,POST比FET稍微安全一些。
如果要真正安全,使用HTTP协议。
3.将HTTP方法类比成SQL动作
GET(select)、POST(insert)、PUT(update)、DELETE(delete)——Restful建议
GET、PUT是幂等的;GET无副作用,PUT有副作用(执行不会影响数据)
POST、DELETE不是幂等的
约束限制等级:无副作用>幂等。无副作用一定幂等,但幂等不一样是无副作用的。
比如,select*from 表 where name= 'x'; 今天、明天、永远执行下去,得到的结果都是一致的,这就是幂等的。反之,同样的语句,第一次成功,以后可能失败,就是不幂等的。
常见场景下的代码片段:
1.输出文本响应
2.读取请求参数
3.重定向redirect (不保留方法的临时重定向 302/307)
HTTP协议: 30X + Location
redirect vs forword(...)
HTTP协议 Servlet内部
3.尝试写一个成绩单
在代码中录入了成绩,然后打印
@WebServlet("/demo-1")
public class Demo1 extends HttpServlet {
//首先把数据准备好
private final HashMap<String,Integer> 成绩单 = new LinkedHashMap<>();
//linkedHashMap元素顺序与插入顺序保持严格一致
// hashMap的元素保存顺序是随机的
public void init() throws ServletException{
成绩单.put("门门",99);
成绩单.put("聪聪",88);
成绩单.put("毛毛",78);
成绩单.put("果果",80);
成绩单.put("小平",60);
//我只要直接在这里添加,就可以显示出来
成绩单.put("嘻嘻",74);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
//我们要输出完整的成绩单
writer.println("<!DOCTYPE html>");
writer.println("<html lang='zh-hans'>");
writer.println("<head>");
writer.println(" <meta charset='utf-8'>");
writer.println(" <title>成绩单</title>");
writer.println("</head>");
writer.println("<body>");
writer.println(" <table border='1'>");
writer.println(" <tbody>");
//这里要遍历成绩单
for (Map.Entry<String, Integer> entry : 成绩单.entrySet()) {
String name = entry.getKey();
int grade = entry.getValue();
writer.println("<tr>");
writer.printf("<td>%s</td> <td>%d</td> ",name,grade);
writer.println("</tr>");
}
writer.println(" </tbody>");
writer.println("</table>");
// writer.println("/<tbody>");
// writer.println("/<body>");
// writer.println("/<html>");
}
}
具体拆分:
代码展示:
ListServlet类:
@WebServlet("/list.html")
//对web链接的引用可以具体到html/css文件的具体格式
public class ListServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html");
PrintWriter writer = resp.getWriter();
//我们要输出完整的成绩单
writer.println("<!DOCTYPE html>");
writer.println("<html lang='zh-hans'>");
writer.println("<head>");
writer.println(" <meta charset='utf-8'>");
writer.println(" <title>成绩单</title>");
writer.println("</head>");
writer.println("<body>");
writer.println(" <table border='1'>");
writer.println(" <tbody>");
//这里要遍历成绩单
for (Map.Entry<String, Integer> entry : GradeRepository.getInstance().map.entrySet()) {
String name = entry.getKey();
int grade = entry.getValue();
writer.println("<tr>");
writer.printf("<td>%s</td> <td>%d</td> ",name,grade);
writer.println("</tr>");
}
writer.println(" </tbody>");
writer.println("</table>");
}
}
SaveServlet类:
@WebServlet("/save")
public class SaveServlet extends HttpServlet {
public static HashMap<String,Integer> map = new HashMap<>();
//这里必须定义成静态属性static,静态属性只有一份
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//需要做三件事
//1.读取
//2.保存
//3.重定向
//通过Post将数据保存
req.setCharacterEncoding("utf-8");
String name = req.getParameter("name");//获取参数
String grade = req.getParameter("grade");
//姓名和成绩不能为空
if(name == null || name.trim().isEmpty()){
System.out.println("姓名不能为空哟~");
//走到这里,用户不按照操作,我们直接返回
return;
}
if(grade == null || name.trim().isEmpty()){
System.out.println("成绩不能为空哟~");
return;
}
int g =0;
try {
g = Integer.parseInt(grade);
}catch (NumberFormatException exc){
System.out.println("输入的成绩不是数字哦~");
}
//2.保存: 保证数据是同一份数据
//上一次我们使用了静态资源,这次使用一个新的方法
GradeRepository.getInstance().map.put(name,g);
//3.重定向
resp.sendRedirect("/list.html");
}
}
GradeRepository类:
//成绩仓库
//要让两个类实现资源共享,使用单例模式
public class GradeRepository {
public final HashMap<String,Integer> map = new HashMap<>();
//这里必须是public ,否则save中无法访问
private final static GradeRepository repository = new GradeRepository();
//这里必须static 才能保证同一份数据 单例模式
protected static GradeRepository getInstance(){
return repository;
}
}
record.html:
<body>
<form method="post" action="/save">
<input type="text" name="name">
<input type="text" name="grade">
<button>提交</button>
</form>
</body>
成绩录入功能{提交页面/列表页面} {/record.html /save /list.html}
红色资源是用户可以直接访问的
1.错误处理(错误排查)
1.这里列举我遇到的:路径缺少404错误
第一次我写的是/list,我以为会自动生成html文件,在浏览器中显示了404错误。
正确的写法:资源路径的引用应该具体到具体文件,比如js,或者html,这样才能查找到
2.开发者工具长期打开
看元素面板的内容是否正确,确保浏览器中的代码和IDEA中的代码是否一致
源码面板
网络面板
查看当前资源的状态,具体可能出现什么错误
控制台
3.具体每层可能出现的问题
网络层(网络不通)
传输层(TCP链接无法建立:Tomcat没有启动、防火墙)
应用层(状态码)
Tomcat启动失败: 1.端口被占用 2.Servlet的URL问题 (开启了多个 或者 没有以/开头)
4. 500错误
@WebServlet("/will-500")
public class ThrowException extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
req.getParameter("username");
req.getParameter("password");
//int n = 1/0;
//除零异常,一定会出现错误
try{
int n = 1/0;
}catch(ArithmeticException e){
throw new RuntimeException(e);
//由于一个算法异常导致了运行时异常
}
}
}
(1)Tomcat内部的问题
(2)代码中出现了异常(观察异常发生的调用栈,找到代码出错的位置)
也可能是代码拼写错误,比如我遇到的,将数据库grades写成了grade,就一直报错
以上展示是专门写的500错误,我个人遇到的500错误,空指针异常,原因是DBUtil没有和数据库建议连接,我只写了return null。
5.辅助方法
添加日志(添加打印)或者多去调试
6.理清我们有多少资源,资源支持方法是什么,资源的Path是什么,资源的职责是什么,资源的关系
2.数据的持久化存储(文件 -> MySQL)
我们已经启动过Tomcat,并且录入了一定的数据。当我们再次重启Tomcat时,成绩单中的数据为空,这是为什么?
数据时保存在GradeRepository的hashMap中,重启Tomcat,就是上一个被暂停,开启了一个新的tomcat,这就是两个tomcat进程,进程和进程之间的数据是隔离的,所以新进程拿不到上一个进程的数据。
1.JDBC
需要引入一个jdbc-mysql的依赖
DataSource对象 Connection对象 PrepareStatement对象 executeUpdate/executeQuery
ResultSet对象 while(rs.next()){...//一行行的去读取}
关联数据库,还需要在pom.xml文件进行修改
显示如下,就说明导入成功
3.拼接HTML比较麻烦(1.模板 2.前后端分离)
主要是针对人的视角
前端通过ajax技术,从后端(通过HTTP协议)读取数据(数据格式JSON为主)
成绩录入——具体实现思路:
类越来越多,为啥需要这么多类?
model包下是承载数据的具体的类,有时候也命名为DataObject DO
写这么多包,是为了方便程序员的阅读
1.承载数据的对象——属性 ( 鱼香肉丝)
序列化:JSON、equals、comparable、hashCode
2.承载流程的对象——方法 (前台、服务员、厨师)
单例的
在不同文件格式下,相互转换用到的方法: