JSP
Java服务器页面,Java Server Pages,动态网页开发技术
页面可包含:指令,脚本(java代码)脚本表达式(输出),声明,HTML,CSS,JSP
JSP实现原理
Tomcat会将xxx.isp转换成Java代码,这个类会继承HttpServlet,进而编译成.class文件运行,最终将运行结果通过response响应给客户端(这个响应会动态使用out.write 拼出一个网页)。
jsp实际上是一个Servlet,响应回游览器的页面中只有HTML的内容了,是被jsp的Servlet write写回来的
脚本
脚本可以编写Java语句,变量,方法或表达式
<%-- 脚本表达式 末尾不可有分号--%>
<%=date%>
<%--声明:成员变量,方法--%>
<%!
private String email="aaa@qq.com";
public String getEmail(){
return email;
}
%>
<br>
<%=email%><br>
<%=getEmail()%>
JSP指令
page指令
一般都不会更改
属性之间加空格
include
被包含的文件不会被编译成class文件
相当于把被包含文件的内容全部copy过来到本文件中,仅仅如此,故要将被包含文件中的除输出语句外的部分删除,这部分指属于HTML文件的部分
动作标签
动作标签是JSP页面在运行期间的命令
被包含文件会被编译为class文件,将其输出结果引入到JSP文件中
生成的对象会被加入到pageContext中
<%--include 导入文件--%>
<jsp:include page="header.jsp"></jsp:include>
<%--useBean 创建类对象--%>
<%-- <%--%>
<%-- User user = new User();--%>
<%-- pageContext.setAttribute("user",user);--%>
<%-- // 这两句话相当于下边的一句话--%>
<%-- %>--%>
<%--这个类必须写全限定名,且类必须在包中--%>
<%--这个对象会被放置到pageContext中--%>
<jsp:useBean id="user" class="com.User"></jsp:useBean>
<%--设置属性--%>
<jsp:setProperty name="user" property="name" value="chichi"></jsp:setProperty>
<%--获得属性 --%>
<jsp:getProperty name="user" property="name"/>
<%--转发,设置编码,防止乱码,接受页面中早已设置好编码,仅有在中间这次转发时编码可能出现问题--%>
<%
request.setCharacterEncoding("utf-8");
%>
<%--转发时传递数据
1.地址后面加参数,添加参数
2.使用jsp:param添加
--%>
<jsp:forward page="login.jsp?username=chichi">
<jsp:param name="username" value="chichi"/>
</jsp:forward>
内置对象
九个
简记 RRSACEOPP
out
out输出内容会先输出到buffer缓冲区(8k)中,再输出到网页中
<% out.println("ccc"); %>
如果想要混用,要对out及时刷新,使用out.flush 方法,否则会出现后写的getWriter().write()会比先写的out.println先一步网页中输出。
pageContext
作用域相当于一个集合
pageContext虽然是最小的,但其功能是最强大的
功能:
1.作为域对象使用
1.1操作当前页面域
1.2操作其他三个作用域
其removeAttribute方法,若不指定具体的域,会把四个域中符合条件的全部删除
2.获取其他八个内置对象
<%
// 1.1 操作当前页面域
pageContext.setAttribute("name","chichi");
String name = (String) pageContext.getAttribute("name");
out.println(name);
// 1.2 操作其他三个域对象
pageContext.setAttribute("requestDate","chichi", PageContext.REQUEST_SCOPE);
// remove方法在不指定域的情况下会删除所有域中name参数相同的
pageContext.removeAttribute("name");
// 按照PRSA的循序一次寻找,找到返回,找不到返回null
pageContext.findAttribute("name");
// 功能2.获取其他八个内置对象
ServletRequest request1 = pageContext.getRequest();
HttpSession session1 = pageContext.getSession();
%>
四大域对象
使用时能用小的就别用大的,从上到下,组件增大
EL表达式
主要用于获取作用域中的数据
没找到返回"" JSP脚本没找会返回null
<%
// 先放域中存放数据
pageContext.setAttribute("username","chichi");
pageContext.setAttribute("password","1234",PageContext.REQUEST_SCOPE);
pageContext.setAttribute("address","上海",PageContext.SESSION_SCOPE);
%>
<%--使用EL表达式获取--%>
${username}<br>
${password}<br>
${address}
<%--获取引用类型的属性--%>
<%
User user = new User("chichi",15,"上海");
pageContext.setAttribute("user",user);
%>
${user}
<%-- 相当于调用get方法--%>
${user.name}
${user.address}
<%--若User还有一个其他类对象,如tel,tel中有个s属性--%>
${user.tel.s}
<%-- EL表达式获取List集合--%>
<%
ArrayList<String> list = new ArrayList<>();
list.add("上海");
list.add("北京");
list.add("广州");
list.add("深圳");
pageContext.setAttribute("city",list);
%>
${city}<br>
${city[0]}<br>
<%-- 下标越界是返回一个""--%>
${city[10]}<br>
${city.get(0)}
<%--数组操作与集合相同 但没有get方法--%>
<%--获取map中数据--%>
<%
HashMap<String,String> map =new HashMap<>();
map.put("chichi","yyds");
map.put("666","000");
pageContext.setAttribute("map",map);
%>
${map}<br>
${map.chichi}
<%-- 数字做键时仅能通过["666"]方式访问--%>
${map["666"]}
eq 等于 lt小于 gt大于 le小于等于 ge 大于等于
<%-- 运算符= - * / %--%>
${10*5}
<%--大小判断--%>
<%-- 字符串可使用== 实际使用equals 比的是指,不是地址--%>
${"abc"=="abc" }<br>
${100 lt 102}<br>
<%--逻辑运算--%>
${true&& false}<br>
${true || false}
${true and false}
${not true};
<%--三目运算符--%>
${gender=="1"?"男":"女"}
<%--判断空值--%>
<%--空字符串,null,空列表 empty判断均为空--%>
<%
pageContext.setAttribute("address","");
pageContext.setAttribute("user",null);
pageContext.setAttribute("list",new ArrayList<String>());
%>
<br>
${empty address}
${empty user}
${empty list}
11个隐式对象
重要四个 pageScope requestScope sessionScope applicationScope,
最重要是pageContext
指定从那个域中取出对象
${requestScope.name}
Param指那些通过表单传入的参数,
<%-- 相当于 getAttritube--%>
${requestScope.name}
<%-- 相当于getParameter--%>
${param.name}
路径分类
<%-- 相当于 getAttritube--%>
${requestScope.name}
<%-- 相当于getParameter--%>
${param.name}
JSTL
是一个标签集合
可对EL获取到的数据进行逻辑操作,为EL完成数据的展示
导入jar包
导入core标签库
<%--导入标签库 c前缀代表后边的 --%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h1>三个通用标签 set out remove</h1>
<%-- 不指定域时 默认放到页面域--%>
<c:set var="username" value="chichi" scope="page"></c:set>
${username}<br>
<%-- 输出内容中有标签 out会编码后输出 直接使用EL表达式会标签写到网站上,被网页识别使用,不安全--%>
<c:out value="使用out输出"></c:out><br>
<c:out value="${username}"></c:out><br>
<%-- remove--%>
<c:remove var="${username}"></c:remove>
if标签
<h1>if标签</h1>
<c:if test="${10>5}">输出内容</c:if>
choose标签
<h1>choose标签</h1>
<c:choose>
<c:when test="${15<5}">输出1</c:when>
<c:when test="${10>5}">输出2</c:when>
</c:choose><br>
遍历forEach标签
varstatus属性值 current返回值 first,last是否开头结尾 index,count下标,分别从0,1开始
<%
ArrayList<String> list = new ArrayList<>();
list.add("苹果");
list.add("苹果");
pageContext.setAttribute("list",list);
HashMap<String, String> map = new HashMap<>();
map.put("apple","苹果");
map.put("ban", "香蕉");
pageContext.setAttribute("map",map);
%>
<%-- 遍历list --%>
<c:forEach var="d" items="${list}">
${d}
</c:forEach>
<%-- 遍历map--%>
<c:forEach var="entry" items="${map}">
${entry.key}---${entry.value}
</c:forEach><br>
<%-- 下角标 vs.index从0开始 vs.count从一开始--%>
<c:forEach var="d" items="${list}" varStatus="vs">
${vs.index}--${vs.count}
</c:forEach><br>
<%-- 输出1到50 间隔1--%>
<c:forEach var="num" begin="1" end="50" step="1">
${num}
</c:forEach>
url标签
会自动带上下文路径,直接写文件名即可
<%-- url标签的使用:把连接进行格式化,自动重写url,自动编码--%>
<c:url value="/servlet" var="myurl">
<c:param name="param1" value="传参"></c:param>
</c:url>
<a href="${myurl}">去主页</a>
时间格式化
导入fmt标签库
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
时间格式化
<%--时间格式化--%>
<%
Date date = new Date();
pageContext.setAttribute("date",date);
%>
<fmt:formatDate value="${date}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>
MVC模式
优缺点
MVC 与三层架构
对应关系
Model :业务层Service ,数据访问层dao
View:JSP
Controller:Servlet 后两者 为三层架构中界面层
基于MVC的三层架构实现
区别
防止表单重复提交
令牌工具类
创建令牌与删除令牌方法
// 令牌生成器
public class TokenUtils {
// 生成随机令牌,放入session中
public static void creatToken(HttpServletRequest request){
try {
request.setCharacterEncoding("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String token = System.currentTimeMillis()+""+new Random().nextInt(99999999);
request.getSession().setAttribute("token",token);
}
// 令牌移除
public static void removeToken(HttpServletRequest request){
request.getSession().removeAttribute("token");
}
}
转账页面
生成令牌,分别保存于服务器与客户端
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>转账页</title>
</head>
<body>
<%
// 生成令牌 并放入服务器Session中
TokenUtils.creatToken(request);
%>
<form method="post" action="${pageContext.request.contextPath}/transservlet">
<table>
<tr>
<th>对方卡号</th>
<th><input type="text" name="toCard" > </th>
// 客户端保存的令牌,表单提交时提交给服务器,用于比较
<input type="hidden" name="token" value="${token}">
</tr>
<tr>
<th>转账金额</th>
<th><input type="text" name="money" > </th>
</tr>
<tr>
<th><input type="submit" value="转账"></th>
</tr>
</table>
</form>
</body>
</html>
令牌比较
重复判断方法,分别判断一下三种情况
1.通过地址栏传入的空令牌
2.通过地址栏传入的不一致令牌
3.正常情况,操作成功后删除了令牌,服务器无令牌,再次提交被判断为重复提交
操作成功后必须移除session中的令牌
private static boolean isRepeat(HttpServletRequest request){
// 通过地址栏传入的空令牌 或者 传入的不一致令牌
String token = request.getParameter("token");
System.out.println(token);
String serverToken = (String) request.getSession().getAttribute("token");
System.out.println(serverToken);
if (StringUtils.isEmpty(token)){
System.out.println(1);
return true;
}
if (!token.equals(serverToken)){
System.out.println(2);
return true;
}
// 正常情况,不通过游览器输出框来传值,重复提交的情况仅有服务器中为空,而表单提交有值
// 操作过后移除Session中令牌,来禁止重复提交
if (StringUtils.isEmpty(serverToken)) {
System.out.println(3);
return true;
}
return false;
}
对两次操作时间间隔加入限制
// 对两次提交的时间间隔限制
long currentTime = System.currentTimeMillis();
Long lastTime = (Long) request.getSession().getAttribute("lastTime");
// 第一次操作时lastTime为空
if (lastTime!=null){
if ((currentTime-lastTime)<60000){
request.setAttribute("message","提交间隔过短");
request.getRequestDispatcher("/message.jsp").forward(request,response);
return;
} }
操作成功后,在Session中放入放入上次操作的时间
request.getSession().setAttribute("lastTime",System.currentTimeMillis());
分页
0902web3
主要有五个核心的元素:
当前页数
页面大小
总的页数
总的数据个数
一页的数据(可以用List存储)
请务必注意查询时使用的值并非当前页码,而是页数与页面大小的乘积,查询时使用中间变量保存
int temp = (pageNum-1)*pageSize;
List<Book> books = bookDao.queryList(temp, pageSize);
long l = bookDao.queryCount();
BookBean<Book> bookBean = new BookBean<>(pageNum,pageSize,l,books );
return bookBean;
优化界面元素,加入开始页码以及结束页码,从而展示页数
创建一个工具类,保存五个元素
// 总页数
private int pageCount;
// 页码
private int pageNum;
// 页大小
private int pageSize;
// 总数据个数
private long totalSize;
// 分页数据
private List<T> data;
// 开始页以及末尾页 共五页,默认1-5页
private int startPage = 1;
private int endPage = 5;
public BookBean( int pageNum, int pageSize, long totalSize, List<T> data) {
this.pageNum = pageNum;
this.pageSize = pageSize;
this.totalSize = totalSize;
this.data = data;
this.pageCount = (int) (totalSize%pageSize ==0?(totalSize/pageSize):(totalSize/pageSize+1));
// 总页数小于页
if (pageCount<5){
endPage = pageCount;
}
// 末尾页限制
if (pageNum>pageCount-4){
startPage=pageCount-4;
endPage=pageCount;
}
// 超过第四页时 页码开始变换
if (pageNum>=4&&pageNum<pageCount){
startPage = pageNum-2;
endPage = pageNum+2;
}
}
public BookBean() {
}
切记,一定要判断字符串是否为null或者是空字符串,集合或者对象一定要判断是否为null或者长度是否大于零。
public class StringUtils {
public static boolean isEmpty(String s){
// 为空时会返回true
return s == null || s.trim().equals("");
}
}