开始时间:2021-07-27
EL工具包
传统方式进行JSP开发
package controller;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class OneServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext application = req.getServletContext();
HttpSession session = req.getSession();
//三种方式添加到作用域对象
application.setAttribute("SID", 001);
session.setAttribute("SName", "Xiaowang");
req.setAttribute("SHome", "Beijing");
//请求转发
req.getRequestDispatcher("/index_1.jsp").forward(req, resp);
}
}
<%--
Created by IntelliJ IDEA.
User: Chenzhijin
Date: 2021/7/28
Time: 9:24
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
//对应方式对应取数据
Integer SID = (Integer) application.getAttribute("SID");
String SName = (String) session.getAttribute("SName");
String SHome = (String) request.getAttribute("SHome");
%>
学员ID:<%=SID%><br/>
学员Name:<%=SName%><br/>
学员Home:<%=SHome%><br/>
用EL表达式来展示
大大提高效率
<hr/>
学员ID:${applicationScope.SID}<br/>
学员Name:${sessionScope.SName}<br/>
学员Home:${requestScope.SHome}<br/>
还可以进一步简化,省略作用域对象的别名
学员ID:${applicationScope.SID}<br/>
学员Name:${sessionScope.SName}<br/>
学员Home:${requestScope.SHome}<br/>
学员Home:${SHome}<br/>
一样能实现输出
但如果有对象不同,但属性名相同的情况
首先定位【pageContext】,再看【request】,然后【session】,最后看【application】
- 容易降低程序执行速度【南辕北辙】
- 容易导致数据定位错误
设计目的,就是简化从pagecontext读取共享数据并输出难度
再看一个例子
req.setAttribute("SHome", "Beijing");
req.setAttribute("key1", "100");
req.setAttribute("key2", 200);
传统方式和EL表达式
<%
String num1 = (String) request.getAttribute("key1");
Integer num2 = (Integer) request.getAttribute("key2");
int sum = Integer.valueOf(num1)+num2 ;
%>
求和结果sum等于:<%=sum%><br/>
EL表达式结果:${key1+key2}
可以用来处理关系表达式
<!--传统Java命令方式实现关系运算输出-->
<%
String age = (String) request.getAttribute("age");
if
(
Integer.valueOf(age) >= 18) {
%>
欢迎光临<br/>
<%
} else {
%>
谢绝入内<br/>
<%
}
%>
EL表达式
${age>=18?"欢迎":"谢绝入内"}
读取请求包内容
键入http://localhost:8080/01_JSP_war_exploded/index_1.jsp?userName=555&password=123
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
来访者姓名:${param.userName}<br/>
来访者密码:${param.password}
若请求参数是[一个请求参数关联多个值]此时可以通过paramValues读取请求参数下指定位置的值并写入到响应体
http://localhost:8080/01_JSP_war_exploded/index_2.jsp?pageNo=1&pageNo=2&pageNo=3
pageNo1:${paramValues.pageNo[0]}<br/>
pageNo2:${paramValues.pageNo[1]}<br/>
pageNo3:${paramValues.pageNo[2]}
得到结果
pageNo1:1
pageNo2:2
pageNo3:3
我们再看一个例子
在question_update.jsp中
<form action="/TestSystem/QuestionUpdate" method="get">
<table border="2">
<tr>
<td>题目编号:</td>
<td><input type="text" name="questionId" value="<%=q.getQuestionId()%>" readOnly></td>
</tr>
<tr>
<td>题目:</td>
<td><input type="text" name="title" value="<%=q.getTitle()%>"></td>
</tr>
<tr>
<td>A:</td>
<td><input type="text" name="optionA" value="<%=q.getOptionA()%>"></td>
</tr>
<tr>
<td>B:</td>
<td><input type="text" name="optionB" value="<%=q.getOptionB()%>"></td>
</tr>
<tr>
<td>C:</td>
<td><input type="text" name="optionC" value="<%=q.getOptionC()%>"></td>
</tr>
<tr>
<td>D:</td>
<td><input type="text" name="optionD" value="<%=q.getOptionD()%>"></td>
</tr>
<tr>
<td>正确答案:</td>
<td>
<input type="radio" name="answer" value="A" <%="A".equals(q.getAnswer())?"checked":""%> >A
<input type="radio" name="answer" value="B" <%="B".equals(q.getAnswer())?"checked":""%> >B
<input type="radio" name="answer" value="C" <%="C".equals(q.getAnswer())?"checked":""%> >C
<input type="radio" name="answer" value="D" <%="D".equals(q.getAnswer())?"checked":""%> >D
</td>
</tr>
<tr>
<td><input type="submit" value="更新试题"/></td>
<td><input type="reset" ></td>
</tr>
</table>
</form>
这种代码也要改为EL表达式
原:
<td><input type="text" name="questionId" value="<%=q.getQuestionId()%>" readOnly></td>
改:
<td><input type="text" name="questionId" value="${requestScope.key.questionId}" readOnly></td>
key后面跟的东西就是前面 name 里的东西
原:
<input type="radio" name="answer" value="A" <%="A".equals(q.getAnswer())?"checked":""%> >A
改
<input type="radio" name="answer" value="A" ${"A" eq key.answer?"checked":""} >A
自动出题功能
在MyLeft.HTML中要添加出题选项
<li>考试管理</li>
<ol>
<li><a href="/TestSystem/QuestionRand" target="right">参加考试</a></li>
<li><a href="/TestSystem/QuestionFind" target="right">试题信息查询</a></li>
</ol>
在题库里随机选择4道题
那么得先构思SQL怎么写
select rand()#随机返回0-1之间的数
select * from question order by rand() limit 0,4
# 此时rand返回的是0-9之间的数 0.6这种值会变为6
# 如果整个序列只有8个字段,那么取9会再取余,用字段1来排序
需要写一个Random的Servlet
package Controller;
@WebServlet(name = "QuestionRandServlet", value = "/QuestionRandServlet")
public class QuestionRandServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.调用DAO对象随机从question表拿出4道题目
QuestionDao dao = new QuestionDao();
List questionList = null;
questionList = dao.findRand();
//2.将4道题目添加到request作为共享数据
request.setAttribute("key", questionList);
//3.请求转发,申请调用exam.jsp将4道题目写入到响应体
request.getRequestDispatcher("/exam.jsp").forward(request, response);
}
}
DAO里面补充方法findRand
基本就是照抄findAll里面的内容,只是sql语句变了一下
public List findRand() {
String sql = "select * from question order by rand() limit 0,4";
PreparedStatement ps = util.createPs(sql);
ResultSet rs = null;
List list = new ArrayList();
try {
rs = ps.executeQuery();
while (rs.next()) {
Integer quesitonId = rs.getInt("questionId");
String title = rs.getString("title");
String optionA = rs.getString("optionA");
String optionB = rs.getString("optionB");
String optionC = rs.getString("optionC");
String optionD = rs.getString("optionD");
String answer = rs.getString("answer");
Question question = new Question(quesitonId, title, optionA, optionB, optionC, optionD, answer);
list.add(question);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
util.close(rs);
}
return list;
}
转发给exam.jsp
所以得补充一个exam.jsp
<%@ page import="Entity.Question" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<center>
<form action="/TestSystem/exam">
<table border="2">
<tr>
<td>试题编号</td>
<td>题目信息</td>
<td>A</td>
<td>B</td>
<td>C</td>
<td>D</td>
<td>答案</td>
</tr>
<%
List<Question> questionList =(List) session.getAttribute("key");
for(Question question:questionList){
%>
<tr>
<td><%=question.getQuestionId()%></td>
<td><%=question.getTitle()%></td>
<td><%=question.getOptionA()%></td>
<td><%=question.getOptionB()%></td>
<td><%=question.getOptionC()%></td>
<td><%=question.getOptionD()%></td>
<td>
<input type="radio" name="answer_<%=question.getQuestionId()%>" value="A"/>A
<input type="radio" name="answer_<%=question.getQuestionId()%>" value="B"/>B
<input type="radio" name="answer_<%=question.getQuestionId()%>" value="C"/>C
<input type="radio" name="answer_<%=question.getQuestionId()%>" value="D"/>D
</td>
</tr>
<%
}
%>
<tr align="center">
<td colspan="3"><input type="submit" value="交卷"></td>
<td colspan="4"><input type="reset" value="重做"></td>
</tr>
</table>
</form>
</center>
</body>
</html>
因为EL不能用来遍历集合,所以还是有部分写的传统的JSP形式
<td>
<input type="radio" name="answer_<%=question.getQuestionId()%>" value="A"/>A
这里的name不能直接写answer,不然四道题16个选项只能选择一个,所以要给4道题分别命名
在线阅卷
阅卷需要将用户提交的答案和设置的答案进行比较,那么需要用session进行数据共享,才能进行验证。
所以就要修改
QuestionRandServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.调用DAO对象随机从question表拿出4道题目
QuestionDao dao = new QuestionDao();
List questionList = null;
//用false防止恶意登录
HttpSession session = request.getSession(false);
questionList = dao.findRand();
//2.将4道题目添加到request作为共享数据
session.setAttribute("key", questionList);
//3.请求转发,申请调用exam.jsp将4道题目写入到响应体
request.getRequestDispatcher("/exam.jsp").forward(request, response);
}
同时修改exam.jsp
获取方式改为
List<Question> questionList =(List) session.getAttribute("key");
写一个ExamServlet用于处理结果
package Controller;
import Entity.Question;
public class ExamServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false);
List<Question> questionList = null;
int score = 0;
//1.从当前用户私人储物柜得到系统提供四道题目信息
questionList = (List) session.getAttribute("key");
//2.从请求包读取用户对于4道题目给出答案
for (Question question : questionList) {
String answer = question.getAnswer();
Integer questionId = question.getQuestionId();
//这里answer_ +questionId 是为了和上传给网页的格式一致
String userAnswer = request.getParameter("answer_" + questionId);
//3.判分
if (userAnswer.equals(answer)) {
score += 25;
}
}
//4.将分数写入到request中,作为共享数据
request.setAttribute("info", "本次考试成绩: " + score);
//5.请求转发调用jsp将用户本次考试分数写入到响应体
request.getRequestDispatcher("info.jsp").forward(request, response);
}
}
网络通信框图
模拟面试
谈谈本次做的在线考试管理系统
功能:
- 用户信息注册、查询
- 试题信息注册、查询
- 考试出题、阅卷
技术:
Servlet、JDBC、MySQL、EL表达式
缺陷:
数据库路径写死了,没有使用反射来配置等
项目介绍
一。项目总体介绍:
1. 介绍项目客户:
2. 介绍项目主要功能
3. 介绍项目使用技术
4. 介绍项目使用服务器
举栗子:
我之前参与 吉林大学在线考试管理系统开发。这个项目主要负责吉大在线考试与在线阅卷功能。
这个系统使用Servlet ,jsp,jdbc,javascript(从服务端向浏览器过渡)
这个系统使用Http服务器是tomcat,使用数据库服务器mysql
二。项目功能介绍:捡主要功能
这个系统大体由【学员信息管理】,【试题信息管理】,【在线考试管理】三个模块组成
三。项目特色介绍:
1.使用监听器模拟了数据库连接池功能,节省Connection创建与销毁时间,提高执行速度
增加QPS(服务器在单位时间接收访问量)
2.使用过滤器防止用户恶意登录行为,增加项目安全性
四。介绍自己在项目参与某一个功能:
参与功能【学员信息注册】
首先根据互联网通信特征,画出来流程图
根据流程图分析开发功能,然后进行开发与测试
什么时候用post 什么时候用get
参考前面的博客
请求方式 | 携带请求参数 | 浏览器地址栏 | 请求参数信息保存在 | 服务器返回的资源文件 |
---|---|---|---|---|
get | 不能超过4K | 必须展示请求参数信息 | Http请求协议包【请求头】 | 保存在浏览器缓存 |
post | 任意数量 | 必须隐藏请求参数信息 | Http请求协议包中【请求体】 | 禁止浏览器保存 |
考虑到POST请求方式,用户可以将【病毒文件内容】发送到服务器上进行攻击。因此绝大多数门户级网站拒绝接收POST请求,日常开发过程绝大多数请求都是GET(不涉及实时变化)
但是注意到坑,get携带参数不能超过4K,但是返回的文件有多大和这个4K没有关系,可以用Get得到大文件的
在某些特殊场景下必须使用POST
- 文件上传,必须使用POST
- 发起登录验证请求,必须使用POST
- 索要服务器中实时变化数据时(股票价格,车票数量。。。),必须采用POST
服务器读取到中文乱码
推测浏览器请求方式为Post
参考博客
浏览器以GET方式发送请求,请求参数保存在==【请求头】,在Http请求协议包到达Http服务器之后,第一件事就是进行解码请求头二进制内容由Tomcat负责解码,Tomcat默认使用【utf-8】字符集,可以解释一切国家文字
浏览器以POST方式发送请求,请求参数保存在【请求体】==,在Http请求协议包到达Http服务器之后,第一件事就是进行解码请求体二进制内容由当前请求对象(request)负责解码。request默认使用[ISO-8859-1]字符集,一个东欧语系字符集此时如果请求体参数内容是中文,将无法解码只能得到乱码
在Post请求方式下,在读取请求体内容之前,应该通知请求对象使用utf-8字符集对请求体内容进行一次重新解码
请求方式 | 请求参数保存在 | 解码 | 解码字符集 |
---|---|---|---|
Get | 请求头 | 由Tomcat负责解码 | 【utf-8】 |
Post | 请求体 | 由当前请求对象(request)负责解码 | 【ISO-8859-1】 |
Servlet里面几种作用域对象
参考博客
作用域对象存在于服务端内存中,为Servlet提供数据共享对象,Cookie存在于浏览器中,虽然能提供共享,但不是作用域对象。
servletcontext接口 | 【全局作用域】对象 |
---|---|
Httpsession接口 | 【会话作用域对象】 |
HttpservletRequest接口 | 【请求作用域对象】 |
cookie和Session区别
参考博客
名称 | Cookie | HttpSession |
---|---|---|
存储位置 | 存放在客户端计算机(浏览器内存/硬盘) | 存放在服务端计算机内存 |
数据类型 | 存储共享数据类型只能是String | 可以存储任意类型的共享数据object |
数据数量 | 一个cookie对象只能存储一个共享数据 | 使用map集合存储共享数据,可以存储任意数量共享数据 |
参照物 | 相当于客户在服务端【会员卡】 | Httpsession相当于客户在服务端【私人保险柜】 |
请求转发和重定向的区别
参考博客
调用规则 | 浏览器发送请求数 | 请求方式 | 响应包返回 | 地址栏 |
---|---|---|---|---|
请求转发 | 1次 | 所有的请求方式和浏览器发过来的保持一致,浏览器用post/get那么Servlet这边也是对应的 | ||
重定向 | 至少2次 | get | 状态码302 | 地址栏会变化 |
多线程工作状态
参考博客
Sql语句执行优先级
优先级 | 语句 |
---|---|
1 | from |
2 | where |
3 | group by |
4 | having |
5 | select |
6 | order by |
count(*)和count(字段)
前者统计临时表总行数为多少
后者统计该字段下内容不为null 的 行数
Java扩容因子
参考博客
HashMap默认初始化容量为16,初始化容量必须是2的倍数,可以提高存取效率。默认加载因子为0.75
意思是当容量用掉75%时,数组开始扩容
在JDK8之后,如果Hash表,单向链表的元素>=8,那么该单向链表会变成红黑树,当红黑树上的节点<6时,红黑树会变回单向链表。为了提高效率,二叉树检索会再次缩小检索范围,初始化容量16,默认加载因子0.75,扩容后容量为原容量2倍
容器 | 容量 | 存储类型 |
---|---|---|
数组 | 一定 | 一种 |
List | 有扩容因子,可增 | 可以多种 |
继承
一个类的构造方法是私有的话,是不可以有子类的
因为创建子类,JVM会先创建一个父类对象,构造方法私有,new不出来
JDBC六步
参考博客
JDBC编程六步
- 第一步:注册驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)
- 第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭
- 第三步:获取数据库操作对象(专门执行sql语句的对象)
- 第四步:执行SQL语句(DQLDML. …)
- 第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)
- 第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程间的通信,开启之后一定要关闭。)
数据库中char和varchar的区别
前者定长不可变,后者定长可变
存储字符串都有空格结尾,存在varchar里面比较好
char自动补齐功能,放三个字符只给了两个,那么最后一个会补齐空格,提取的时候会砍掉结尾空格
结束时间:2021-08-30