一.处理各种表单请求参数
1.日期类型的参数:注意要将日期进行格式化,然后转化为java中的date类型
2.单选按钮的参数:传过来的参数值可能会是中文,所以在java代码中要进行字符编码设置setCharacterEncoding();
3.多选按钮:注意返回的是字符串数组,所以要进行数组是否为空的判断,否则可能会出现空指针异常
4.下拉列表:在没有设置value的情况下,会将标签中的文字当做value进行处理
5.文本域:和普通文本框差不多
详情代码如下:
<%--
Created by IntelliJ IDEA.
User: Szy
Date: 2018/10/16
Time: 19:47
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/FormEleTest" method="post">
<p><input type="date" name="birthday"></p>
<hr>
男<input type="radio" name="sex" value="男" checked> <%--默认选中--%>
女<input type="radio" name="sex" value="女">
<hr>
唱歌<input type="checkbox" name="hobby" value="唱歌">
跳舞<input type="checkbox" name="hobby" value="跳舞">
书法<input type="checkbox" name="hobby" value="书法">
国画<input type="checkbox" name="hobby" value="国画">
<hr>
<%--如果不提供value属性,则会把标签之间的文本当做value考虑
如果提供value,则优先使用value的值--%>
<select name="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="陕西">陕西</option>
<option value="深圳">深圳</option>
</select>
<hr>
个人简介<textarea name="intro" cols="30" rows="10"></textarea>
<p><input type="submit" value="提交"></p>
</form>
</body>
</html>
package level3;
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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
//关于日期表单格式的测试
@WebServlet(urlPatterns = "/FormEleTest")
public class FormEleTest extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8"); //设置字符编码,防止出现中文乱码
//处理日期类型
String birthday = req.getParameter("birthday"); //得到jsp中的birthday
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //格式化日期为固定形式
try {
Date date = sdf.parse(birthday); //转化为date类型
System.out.println(date); //打印到控制台
} catch (ParseException e) {
e.printStackTrace();
}
//处理单选按钮
String sex = req.getParameter("sex");
System.out.println(sex);
//处理多选按钮
// 注意:因为是多选按钮,所以会有多个值,要用getParameterValues(),返回的是一个字符串数组类型
String[] hobbies = req.getParameterValues("hobby");
//System.out.println(Arrays.toString(hobbies));
//但是如果对复选框一个按钮也没有选择,就会打印出错,出现空指针异常
// 因此在这之前要对hobbies数组进行是否为空的判断
if(hobbies != null) {
System.out.println(Arrays.toString(hobbies));
}
//处理下拉列表
String city = req.getParameter("city");
System.out.println(city);
//处理文本域 ps:处理文本域其实和处理普通文本框差不多
String intro = req.getParameter("intro");
System.out.println(intro);
}
}
执行结果:
二.jstl的标签
1.c:choose 类似于 if elseif else
语法:
<c:choose>
<c:when test="条件1">内容1</c:when>
<c:when test="条件2">内容2</c:when>
...
<c:when test="条件n">内容n</c:when>
<c:otherwise>以上条件都不成立时</c:otherwise>
</c:choose>
2.c:out 用来输出特殊内容
它可以对${}输出的内容进行控制,可以控制是否忽略html代码
<c:out escapeXML="false" value="${作用域变量}"> 不忽略html
<c:out escapeXML="true" value="${作用域变量}"> 忽略html,(当做普通文本)
3.格式化日期或数字
<fmt:formatDate value="日期对象" pattern="日期格式"/>
<fmt:formatNumber value="数字对象" pattern="数字格式"/>
数字格式 `#` 和 `0` 其中0可以用来前置补零或后置补零,能够自动进行四舍五入
测试代码:
<%--
Created by IntelliJ IDEA.
User: Szy
Date: 2018/10/22
Time: 16:53
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--choose标签 相当于if-if-else语句 里面的并且可以有"and"和"&&"两种表达方式--%>
<c:choose>
<c:when test="${salary < 3000}">低收入</c:when>
<c:when test="${salary > 3000 and salary < 8000}">中等收入</c:when>
<c:when test="${salary >= 8000 && salary < 15000}">较高收入</c:when>
<c:otherwise>高收入</c:otherwise>
</c:choose>
<hr>
<%--escapeXML是是否忽略掉HTML语法 false是不忽略--%>
<c:out value="${text}"></c:out>
<hr>
<c:out value="${text}" escapeXml="false"></c:out>
<hr> <%--把日期格式化为预期的样子--%>
<fmt:formatDate value="${birthday}" pattern="yyyy-MM-dd"></fmt:formatDate>
<hr> <%--格式化数字,如保留几位小数,是否用0填充 ps:可以自动四舍五入--%>
<fmt:formatNumber value="${num}" pattern="####.##"></fmt:formatNumber><hr>
<fmt:formatNumber value="${num}" pattern="0000.##"></fmt:formatNumber>
</body>
</html>
package level3;
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.Date;
@WebServlet(urlPatterns = "/JstlTabTest")
public class JstlTabTest extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//choose测试
/**
* 判断salary,salary<3000 ---> 低工资
* salary>3000 && salary < 8000 ---> 中等工资
* salary>=8000 ---> 高工资
*/
req.setAttribute("salary", 4500);
//out测试
req.setAttribute("text", "<span style='color:red; font-size:5em;'>文字</span>");
//fmt测试
req.setAttribute("birthday", new Date());
req.setAttribute("num", 123.456);
//跳转页面
req.getRequestDispatcher("jstlTab.jsp").forward(req, resp);
}
}
测试结果:
三.jsp指令
<%@ page contentType="页面的内容类型和编码"
import="要导入的java类"
isELIgnored="是否忽略EL表达式的处理"
errorPage="出现错误时,要跳转的页面"
isErrorPage="用在错误页面上,取值为true表示是错误页面,这时候才能在页面中使用exception变量"
%>
可以用exception说明具体异常,但只能配合jsp表达式和jsp脚本使用
<%@ taglib prefix="前缀" uri="标签的唯一标识" %> 作用是导入标签库
<%@ include file="另一个jsp页面" %> 作用是重用页面上的一些标签和代码
四.jsp原理(jsp本质上式servelt) 执行jsp代码底层会将其翻译成servlet代码
看如下示例代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%!
int i = 100; //定义在声明部分的变量,是实例变量,其优先级低于局部变量
public int sum(int a, int b) {
return a + b;
}
%>
<% int i = 10; //在脚本部分的变量是一个局部变量 %>
<%--输出--%>
<%= i %> <%--测试1:检测输出哪一个i变量--%>
<%= i++ %> <%--测试2:不断刷新页面后,i的值是否今次那个自增--%>
<%= i++%> <%--测试3:在注释掉第21行代码之后,不断刷新页面i变量是否会进行自增--%>
</body>
</html>
在<!%...%>的java代码里定义一个变量i,在<%...%>的HTML代码中定义一个变量i,然后按要求进行测试,得到测试结果
测试1:输出i的变量值为10
测试2:i不能进行自增
测试3:i从100开始,没刷新以此页面,i自增1
代码原理分析:
jsp 要工作,也必须编译为java类,如下代码
首先因为就近先打印局部变量(脚本中的值)i=10,刷新页面,方法重新调用,每次都会重置为初始值
注释掉之后,就用的是成员变量i=100,就算不断刷新页面,但底层用的是同一个jsp对象,所以值会进行自增
public class 类名 extends HttpJspBase{ // HttpJspBase 又是继承了HttpServlet
public int i = 100;
public int sum(int a, int b) {
return a+b;
}
public void _jspService(HttpServletRequest request,
HttpServletResponse response) {
int i = 10;
out.println(i++);
}
}
因此,jsp的底层执行:
1) 当首次访问此jsp时,tomcat会把jsp转译为*.java的类(间接继承自HttpServlet)
2) 再把*.java类编译为*.class字节码
3) 把加载到虚拟机执行,生命周期类似于servlet的生命周期
五.大隐式对象(无需声明即可使用)
request 代表请求对象(可以获取请求参数,将变量存入request作用域)
response 代表响应对象(返回响应)
out 代表响应的字符输出流
pageContext 页面上下文对象,可以间接获得request等对象,并可以将变量存入page作用域
config jsp的配置信息
page 当前jsp对象(this)
exception 代表的是异常信息(当页面isErrorPage="true"时有效)
session 变量作用范围是一次会话内有效
application 变量作用范围是整个应用程序有效
page作用域: 变量作用范围仅限于当前页面
request作用域: 变量的作用范围在一次请求内有效
六.cookie
1.cookie的创建
package level3.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/CreateCookieTest")
public class CreateCookieTest extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建一个cookie对象
Cookie c = new Cookie("name", "zhangsan");
//通过响应反馈给浏览器
resp.addCookie(c);
//成功后进行提示
resp.getWriter().println("<html><body>cookie created...</body></html>");
}
}
执行结果:
结果可以在谷歌浏览器中查看,发现存在zhangsan这个cookie
但是这是属于会话层的,一旦浏览器关闭,那么存储到信息会删除,如果想要让cookie存在的时间更长一些,可以使用c.setMaxAge("时间")来指定存储时间,存储的名字如果是中文,为防止乱码,需要将中文用URLEncoding.encode("中文","utf-8)进行解码
2.获取所有的cookie
package level3.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet(urlPatterns = "/GetCookieTest")
public class GetCookieTest extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies = req.getCookies();
for (Cookie cookie : cookies) {
System.out.println(cookie.getName() + "---" + cookie.getValue());
}
}
}
执行结果
七.Session
session 必须针对同一个浏览器,才能实现在请求存储信息,在之后的请求获取信息的效果
每个用户访问服务器时,服务器会为他们创建一个独立的session
1) 首次创建session时,tomcat会产生一个名为`JSESSIONID=session的唯一标识` 的特殊cookie
这个`JSESSIONID=1`就会随着响应返回给浏览器
2) 浏览器会记录这个cookie。之后的所有请求会把此cookie发送给服务器。
服务器根据cookie的值找到对应的session
3) jsessionid 这个cookie属于会话cookie,浏览器关闭就会消失
HttpSession session = request.getSession();
首次调用getSession方法就是创建session对象
后续再调用getSession方法是获取第一次创建好的session对象
存入内容
session.setAttribute("变量名", 任意信息);
获取内容
Obejct 信息 = session.getAttribute("变量名");
删除内容
Obejct 信息 = session.removeAttribute("变量名");
让session失效(会清空session中所有内容)
session.invalidate();
1.创建session对象
package level3.session;
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.servlet.http.HttpSession;
import java.io.IOException;
import java.net.HttpCookie;
@WebServlet(urlPatterns = "/CreateSessionTest")
public class CreateSessionTest extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建或获取session对象
HttpSession session = req.getSession();
//存入信息
session.setAttribute("name", "李四");
resp.getWriter().println("<html><body>session created...</body></html>");
}
}
运行结果:
2.获取session对象中已经存储的信息
package level3.session;
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.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet(urlPatterns = "/GetSessionTest")
public class GetSessionTest extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取CreateSessionTest中创建的session对象信息
HttpSession session = req.getSession();
Object name = session.getAttribute("name");
System.out.println(name);
}
}
运行结果:
对比session和cookie
1) session是将信息存储于服务器端,cookie是将信息存储于浏览器端
2) session与cookie相比,更为安全
3) session的生命周期相对较短,
两次请求间隔超过30分钟,服务器会销毁session
调用session.invalidate方法时,会立刻销毁
cookie
会话cookie是浏览器关闭就销毁
setMaxAge的cookie会根据设置的寿命存活一段时间
4) 存储的信息量上
cookie 每个最大大小是4k左右
session 理论上没有限制,但session要占用服务器内存,所以不太适合存储太多的内容
信息要永久存储,还是需要使用数据库
5) cookie里数据都得是字符串,而session里可以存储任意类型
八.Session的应用---用户登录
如果未登录,跳转到登录页面,如果登陆成功了,则可以对商品进行管理
登录的实现代码
package level3.session;
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.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet(urlPatterns = "/LoginTest")
public class LoginTest extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置字符编码
req.setCharacterEncoding("utf-8");
//获取jsp提交的信息
String username = req.getParameter("username");
String password = req.getParameter("password");
//对提交的用户信息进行判断,如果判断成功,存储登录标记,并跳转到欢迎界面
if("zhangsan".equals(username) && "123".equals(password)) {
HttpSession session = req.getSession();
session.setAttribute("islogin", true);
session.setAttribute("username", username);
req.getRequestDispatcher("welcome.jsp").forward(req, resp);
} else {
//否则跳转到登录页面重新登录
req.getRequestDispatcher("login.jsp").forward(req, resp);
}
}
}
登录的界面代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/LoginTest" method="post">
<input type="text" name="username">
<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
添加商品代码
package level3.session;
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.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet(urlPatterns = "/ProductAdd")
public class ProductAdd extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取session中的登录标记
HttpSession session = req.getSession();
//如果登录标记为空,则跳转到登录页面,否则打印添加商品信息
if(session.getAttribute("islogin") == null) {
req.getRequestDispatcher("login.jsp").forward(req, resp);
return;
}
System.out.println("添加商品成功!");
}
}
九、请求重定向
请求转发:
request.getRequestDispatcher("目录路径").forward(request,response);
请求重定向:
response.sendRedirect("目录路径");
区别:
1) 请求转发时,地址栏不会改变(是第一个servlet的地址)
重定向,地址栏会发生变化(是最后一个servlet的地址)
2) 请求转发时一次请求,跳转发生在服务器内部
重定向是两次请求,第一次请求会返回302的状态码和目标地址,
浏览器根据目标地址发送第二次请求,才完成整个流程
3) 重定向是两次请求,所以不能利用request作用域存值取值
但可以使用session作用域来存值取值
请求转发因为是同一次请求,所以可以使用request作用域存值取值
4) 请求转发的目标只能是本项目的servlet或jsp
重定向跳转的目标可以是任意的
请求转发和请求重定向的执行过程图解