JavaWeb基础恢复之开门篇
2018-04-17 本文已影响34人
平安喜乐698
目录
0. 环境配置
1. 创建WebService项目,创建Servlet
2. Servlet基础知识点
3. jsp基础知识点
4. JavaBean
5. 架构模式
0. 环境配置
Eclipse官网下载
Tomcat下载
MyEclipse官网下载(Mac版请参见 常用网址文章篇下载)
配置Tomcat(myEclipse默认自带)
1. 下载tomcat Core下zip,解压到/Library,改名为Tomcat。
cd /Library/Tomcat/bin。
sudo sh startup.sh 开启服务(出错则chmod +x *.sh)
sudo sh startup.sh 关闭服务器
浏览器输入:http://localhost:8080/ 服务器开启则正常显示(则配置成功)
2. MyEclipse
Window | Show View | servers 出现视图后右键添加Servie(选择/Library/Tomcat/)
3. 其他(添加用户)
编辑/Tomcat/conf/tomcat-users.xml
<user username="admin" password="admin" roles="manager"/>
1. 创建一个WebService项目
1、项目栏空白处,右键 创建web项目
2、选中项目,右键 运行项目
项目栏空白处右键
选中项目右键
运行结果
3、在src下创建包
4、在包下创建Servlet
访问时路径http://localhost:8093/ProjectTestOne/TestServlet,因为doGet没有任何代码,所以会显示空白页面。
新版本:
@WebServlet("/TestServlet") 注解映射
以前的版本:
会在web.xml中自动生成如下代码(映射配置),而不是使用注解
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.sst.cx.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/servlet/HelloServlet</url-pattern>
</servlet-mapping>
在包下创建Servlet
Servlet-1
Servlet-2
Servlet-3 Servlet
5、做个简单的小改变。修改doGet方法并运行,再次访问该Servlet,代码如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.print(" This is ");
out.print(this.getClass());
out.println(", using the GET method");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
Servlet界面
2. Servlet基础知识点
- 服务器收到客户端的Servlet请求后的流程
①检查是否已创建该Servlet实例对象。如果是,则直接执行第③步,否则,执行第②步。
②创建该Servlet实例对象,调用init()方法。
③创建一个HttpServletRequest对象(用于封装HTTP请求消息:存储客户端提交过来的数据)和一个HttpServletResponse对象(用于封装HTTP响应消息:用于向客户端传递数据),然后调用Servlet的service()方法(2个对象作为参数)。
④WEB应用程序被停止或重新启动前,Servlet引擎将卸载Servlet(卸载前调用destroy()方法)。
可以看出:
1、Servlet实例对象创建后直至web容器退出才会销毁。
2、init方法只被调用一次。service方法在每一次请求都会调用,并新建请求和响应对象调用GET/POST。
一次完整请求流程
- HttpServlet
在原有Servlet接口上添加了一些HTTP协议处理方法,比原有Servlet接口的功能更为强大,它覆写了service方法,会自动判断用户的请求方式去调用GET/POST。
因此,在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。
public class HelloServlet extends HttpServlet{
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
}
- HttpServletRequest
用于封装HTTP请求消息:存储客户端提交过来的数据
URL地址
// 获取URL地址
String requestUrl = request.getRequestURL().toString();
// 获取URL地址后边的资源路径(域名以后)
String requestUri = request.getRequestURI();
// 获取URL地址中的参数
String queryString = request.getQueryString();
当前访问用户相关
// 获取当前访问用户的IP地址
String remoteAddr = request.getRemoteAddr();
// 获取当前访问用户的主机名
String remoteHost = request.getRemoteHost();
// 获取当前访问用户的端口
int remotePort = request.getRemotePort();
//
String remoteUser = request.getRemoteUser();
GET/POST
// GET/POST
String method = request.getMethod();
//
String pathInfo = request.getPathInfo();
WEB服务器
// 获取WEB服务器的IP地址
String localAddr = request.getLocalAddr();
// 获取WEB服务器的主机名
String localName = request.getLocalName();
请求头各个参数
// 获取所有的请求头
Enumeration<String> reqHeadInfos = request.getHeaderNames();
// 循环遍历
while (reqHeadInfos.hasMoreElements()) {
String headName = (String) reqHeadInfos.nextElement();
String headValue = request.getHeader(headName);
}
// 获取指定请求头对应的值
String value = request.getHeader("Accept-Encoding");
// 循环遍历
Enumeration<String> e = request.getHeaders("Accept-Encoding");
while (e.hasMoreElements()) {
String string = (String) e.nextElement();
}
获取参数值(常用)
// 保持编码统一(防止POST提交出现乱码,避免不了GET)
request.setCharacterEncoding("UTF-8");
// 获取指定参数值
String username = request.getParameter("username");
// 解决GET提交出现乱码
name =new String(username.getBytes("ISO8859-1"), "UTF-8") ;
// 对url中的中文处理
// ...&name=<%=URLEncoder.encode("徐达沛", "UTF-8")%>
// 获取指定参数值(多个)
String[] insts = request.getParameterValues("inst");
// 获取所有的参数名(不常用)
Enumeration<String> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String name = paramNames.nextElement();
String value = request.getParameter(name);
}
// request对象封装的参数是以Map的形式存储的
Map<String, String[]> paramMap = request.getParameterMap();
for(Map.Entry<String, String[]> entry :paramMap.entrySet()){
String paramName = entry.getKey();
String paramValue = "";
String[] paramValueArr = entry.getValue();
for (int i = 0; paramValueArr!=null && i < paramValueArr.length; i++) {
if (i == paramValueArr.length-1) {
paramValue+=paramValueArr[I];
}else {
paramValue+=paramValueArr[i]+",";
}
}
}
传值
// 添加
request.setAttribute("data", data);
// 移除
request.removeAttribute("data");
// jsp使用
<%=(String)request.getAttribute("data")%>
// jsp获取所有参数名
Enumeration<String> attrNames = request.getAttributeNames();
转发/重定向
一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理,称之为请求转发/307。
一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源进行处理,称之为请求重定向/302。
方法一
RequestDispatcher reqDispatcher =this.getServletContext().getRequestDispatcher("/test.jsp");
reqDispatcher.forward(request, response);
方法二
request.getRequestDispatcher("/test.jsp").forward(request, response);
- HttpServletResponse
用于向客户端传递数据(封装了向客户端发送的 数据、响应头、响应状态码)。
向客户端(浏览器)发送数据
两个方法冲突(调用了其中的任何一个方法后,就不能再调用另一方法)
方法一
OutputStream流(是字节流即二进制数据,可以处理任意类型的数据)
ServletOutputStream stream=response.getOutputStream();
String data = "中国";
// 获取OutputStream输出流
OutputStream outputStream = response.getOutputStream();
// 设置浏览器编码(需要一致,否则乱码)
response.setHeader("content-type", "text/html;charset=UTF-8");
// 将字符转换成字节(需要转码)数组,指定以UTF-8编码进行转换,如果不带参数则会根据操作系统的语言环境(中文操作系统使用GB2312的码表)来选择转换码表。
byte[] dataByteArr = data.getBytes("UTF-8");
// 写入数据
outputStream.write(dataByteArr);
// 不能直接输入数字
// outputStream.write((1+"").getBytes());
方法二
PrintWriter流(是字符流即文本数据,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失)
// 必须先设置编码,后创建输出。否则无效
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
// 设置浏览器编码
response.setHeader("content-type", "text/html;charset=UTF-8");
out.write(1+"");
out.println("<HTML>");
out.flush();
out.close();
向客户端(浏览器)发送响应头
response.addDateHeader(arg0, arg1);
response.addHeader(arg0, arg1);
response.addIntHeader(arg0, arg1);
if(response.containsHeader(arg0)){}
response.setDateHeader(arg0, arg1);
response.setHeader(arg0, arg1);
response.setIntHeader(arg0, arg1);
例:
response.setDateHeader("expries", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
【定时刷新】设置refresh响应头控制浏览器每隔5秒钟刷新一次
response.setHeader("refresh", "5");
【请求重定向】
response.sendRedirect("/JavaWeb_HttpServletResponse_Study_20140615/index.jsp");
向客户端(浏览器)发送响应状态码
response.setStatus(arg0);
响应状态码常量
状态码404:
状态码200:
状态码500:
状态码302:HttpServletResponse.SC_FOUND
HttpServletResponse 使用实例
例1:下载文件(从网站上)
// 1.获取要下载的文件的绝对路径
String realPath = this.getServletContext().getRealPath("/download/1.JPG");
// 2.获取要下载的文件名
String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
// 3.设置content-disposition响应头控制浏览器以下载的形式打开文件
response.setHeader("content-disposition", "attachment;filename="+fileName);
// 3.文件名含中文需要+
response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
// 4.获取要下载的文件输入流
InputStream in = new FileInputStream(realPath);
int len = 0;
// 5.创建数据缓冲区
byte[] buffer = new byte[1024];
// 6.通过response对象获取OutputStream流
OutputStream out = response.getOutputStream();
// 7.将FileInputStream流写入到buffer缓冲区
while ((len = in.read(buffer)) > 0) {
// 8.使用OutputStream将缓冲区的数据输出到客户端浏览器
out.write(buffer,0,len);
}
in.close();
例2:随机数图片
<img alt="验证码看不清,换一张" src="${pageContext.request.contextPath}/servlet/DrawImage" id="validateCodeImg" onclick="changeImg()">
// 设置refresh响应头控制浏览器每隔5秒钟刷新一次
response.setHeader("refresh", "5");
// 1.在内存中创建一张图片,并获取
BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
//Graphics g = image.getGraphics();
Graphics2D g = (Graphics2D)image.getGraphics();
// 1.1 设置图片的背景色,并填充
g.setColor(Color.WHITE);
g.fillRect(0, 0, 80, 20);
// 1.2 设置边框色,并描边
g.setColor(Color.RED);
g.drawRect(1, 1, WIDTH - 2, HEIGHT - 2);
// 1.3 向图片上写数据(设置图片上颜色、字体、文本)
g.setColor(Color.BLUE);
g.setFont(new Font(null, Font.BOLD, 20));
g.drawString(makeNum(), 0, 20);
// 将随机数存在session中
request.getSession().setAttribute("checkcode", 随机数);
// 2.设置响应头控制浏览器浏览器以图片的方式打开
response.setContentType("image/jpeg");//等同于response.setHeader("Content-Type", "image/jpeg");
// 3.设置响应头控制浏览器不缓存图片数据
response.setDateHeader("expries", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
// 4.将图片写给浏览器
ImageIO.write(image, "jpg", response.getOutputStream());
/**
* 生成随机数字
* @return
*/
private String makeNum(){
Random random = new Random();
String num = random.nextInt(9999999)+"";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 7-num.length(); i++) {
sb.append("0");
}
num = sb.toString()+num;
return num;
}
其他方法
//String random = drawRandomNum((Graphics2D) g,"ch");//生成中文验证码图片
//String random = drawRandomNum((Graphics2D) g,"nl");//生成数字和字母组合的验证码图片
//String random = drawRandomNum((Graphics2D) g,"n");//生成纯数字的验证码图片
//String random = drawRandomNum((Graphics2D) g,"l");//生成纯字母的验证码图片
/**
* 在图片上画随机线条
* @param g
*/
private void drawRandomLine(Graphics g) {
// 设置颜色
g.setColor(Color.GREEN);
// 设置线条个数并画线
for (int i = 0; i < 5; i++) {
int x1 = new Random().nextInt(WIDTH);
int y1 = new Random().nextInt(HEIGHT);
int x2 = new Random().nextInt(WIDTH);
int y2 = new Random().nextInt(HEIGHT);
g.drawLine(x1, y1, x2, y2);
}
}
/**
* 画随机字符
* @param g
* @param createTypeFlag
* @return
* String... createTypeFlag是可变参数,
* Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。注意:可变参数必须位于最后一项
*/
private String drawRandomNum(Graphics2D g,String... createTypeFlag) {
// 设置颜色
g.setColor(Color.RED);
// 设置字体
g.setFont(new Font("宋体", Font.BOLD, 20));
//常用的中国汉字
String baseChineseChar = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6";
//数字和字母的组合
String baseNumLetter = "0123456789ABCDEFGHJKLMNOPQRSTUVWXYZ";
//纯数字
String baseNum = "0123456789";
//纯字母
String baseLetter = "ABCDEFGHJKLMNOPQRSTUVWXYZ";
//createTypeFlag[0]==null表示没有传递参数
if (createTypeFlag.length > 0 && null != createTypeFlag[0]) {
if (createTypeFlag[0].equals("ch")) {
// 截取汉字
return createRandomChar(g, baseChineseChar);
}else if (createTypeFlag[0].equals("nl")) {
// 截取数字和字母的组合
return createRandomChar(g, baseNumLetter);
}else if (createTypeFlag[0].equals("n")) {
// 截取数字
return createRandomChar(g, baseNum);
}else if (createTypeFlag[0].equals("l")) {
// 截取字母
return createRandomChar(g, baseLetter);
}
}else {
// 默认截取数字和字母的组合
return createRandomChar(g, baseNumLetter);
}
return "";
}
/**
* 创建随机字符
* @param g
* @param baseChar
* @return 随机字符
*/
private String createRandomChar(Graphics2D g,String baseChar) {
StringBuffer sb = new StringBuffer();
int x = 5;
String ch ="";
// 控制字数
for (int i = 0; i < 4; i++) {
// 设置字体旋转角度
int degree = new Random().nextInt() % 30;
ch = baseChar.charAt(new Random().nextInt(baseChar.length())) + "";
sb.append(ch);
// 正向角度
g.rotate(degree * Math.PI / 180, x, 20);
g.drawString(ch, x, 20);
// 反向角度
g.rotate(-degree * Math.PI / 180, x, 20);
x += 30;
}
return sb.toString();
}
其他
// 用来获取服务器上的某个资源
this.getServletContext().getRealPath("/download/1.JPG");
// 跳转到其他页面
this.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
<%@include file="/jspfragments/head.jsp" %>
<jsp:include page="/jspfragments/demo.jsp" />
// 重定向
response.sendRedirect(request.getContextPath()+"/index.jsp");
// 超链接跳转
<a href="${pageContext.request.contextPath}/index.jsp">跳转到首页</a>
// Form表单提交
<form action="${pageContext.request.contextPath}/servlet/CheckServlet" method="post">
<input type="submit" value="提交">
</form>
<%--使用绝对路径的方式引用js、css--%>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/index.js"></script>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/index.css" type="text/css"/>
<%--${pageContext.request.contextPath}与request.getContextPath()写法是得到的效果是一样的--%>
<script type="text/javascript" src="<%=request.getContextPath()%>/js/login.js"></script>
- 相关
线程安全问题
当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。
如:doGet方法中访问全局变量,且多个客户端同时访问会导致此安全问题
解决:
synchronized (this) {
// 在java中,每一个对象都有一把锁,这里的this指的就是Servlet对象
}
缓存
设置合理的缓存时间值,避免浏览器频繁向服务器发送请求,提升服务器的性能
response.setDateHeader("expires",System.currentTimeMillis() + 24 * 3600 * 1000);
// 然后调用response.getOutputStream().write(data.getBytes());
<servlet>说明
<servlet-mapping>为映射路径(可以有多个)
servlet-name:可以改,保持一致即可
*通配符,任意字符。/* 或 *.hello
<servlet>中 + <load-on-startup>1</load-on-startup>
可以在启动时就创建Servlet的实例对象,并调用init方法
/ 缺省Servlet。找不到Servlet时都会调这个
/Tomcat/conf/web.xml中设置如下默认缺省值
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
初始化参数<init-param>
当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。
WEB容器在启动时为每个WEB应用程序都创建一个对应的ServletContext对象(代表当前web应用,所有Servlet共享同一个,可借此通讯)可通过ServletConfig.getServletContext方法获得ServletContext对象。
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.sst.cs</servlet-class>
<init-param>
<param-name>name</param-name>
<param-value>hello</param-value>
</init-param>
</servlet>
private ServletConfig config;
public void init(ServletConfig config) throws ServletException {
this.config = config;
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取在web.xml中配置的初始化参数
//获取指定的初始化参数
String paramVal = this.config.getInitParameter("name");
response.getWriter().print(paramVal);
response.getWriter().print("<hr/>");
// 获取所有的初始化参数
Enumeration<String> e = config.getInitParameterNames();
while(e.hasMoreElements()){
String name = e.nextElement();
String value = config.getInitParameter(name);
response.getWriter().print(name + "=" + value + "<br/>");
}
}
ServletContext
1、不同Servlet间通讯
Servlet1
// 获得ServletContext对象
ServletContext context = this.getServletConfig().getServletContext();
// 设值
context.setAttribute("data", data);
Servlet2
// 获得ServletContext对象
ServletContext context = this.getServletConfig().getServletContext();
// 取值
String data = (String) context.getAttribute("data");
2、取WEB应用的初始化参数
web.xml下
<!-- 配置WEB应用的初始化参数 -->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/test</param-value>
</context-param>
// 获取
ServletContext context = this.getServletContext();
String contextInitParam = context.getInitParameter("url");
3、请求转发
//获取ServletContext对象
ServletContext context = this.getServletContext();
//获取请求转发对象(RequestDispatcher)
RequestDispatcher rd = context.getRequestDispatcher("/servlet/ServletContextDemo5");
//调用forward方法实现请求转发
rd.forward(request, response);
4、读取资源文件
response.setHeader("content-type","text/html;charset=UTF-8");
InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/gacl/servlet/study/db4.properties");
Properties prop = new Properties();
prop.load(in);
String driver = prop.getProperty("driver");
会话
用户打开一个浏览器直到关闭前的整个过程称之为一个会话。保存会话数据的两种技术:
1.Cookie客户端技术
将每个用户的数据以cookie的形式存储到浏览器。当用户使用浏览器再去访问服务器中的web资源时,可以回显数据。
2.Session是服务器端技术
服务器为每个用户的浏览器创建一个其独享的session对象来存储数据,当用户再去访问服务器中的其它web资源时,可以从session中取出数据。
Cookie
浏览器一般只允许存放300个Cookie
每个站点最多存放20个Cookie
每个Cookie的大小限制为4KB
例:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置服务器端以UTF-8编码进行输出
response.setCharacterEncoding("UTF-8");
// 设置浏览器以UTF-8编码进行接收,解决中文乱码问题
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// 获取浏览器的cookie数组
Cookie[] cookies = request.getCookies();
// 如果用户是第一次访问,那么得到的cookies将是null
if (cookies!=null) {
out.write("您上次访问的时间是:");
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[I];
if (cookie.getName().equals("lastAccessTime")) {
Long lastAccessTime =Long.parseLong(cookie.getValue());
Date date = new Date(lastAccessTime);
out.write(date.toLocaleString());
}
}
}else {
out.write("这是您第一次访问本站!");
}
// 用户访问过之后重新设置用户的访问时间,存储到cookie中,然后发送到客户端浏览器
// 创建一个cookie,cookie的名字是lastAccessTime
Cookie cookie = new Cookie("lastAccessTime", System.currentTimeMillis()+"");
// 设置Cookie的有效期为1天(否则关闭浏览器则失效)
cookie.setMaxAge(24*60*60);
// 删除此Cookie
// cookie.setMaxAge(0);
// 将cookie对象添加到response对象中,这样服务器在输出response对象中的内容时就会把cookie也输出到客户端浏览器
response.addCookie(cookie);
/*
// Cookie中含有中文
// 设
Cookie cookie = new Cookie("userName", URLEncoder.encode("你好", "UTF-8"));
// 取
URLDecoder.decode(cookies[i].getValue(), "UTF-8")
*/
}
Session
服务器创建session后,会把session的id号以cookie的形式回写给客户端,浏览器再去访问服务器时都会带着session的id号。
session对象默认30分钟没有使用则服务器会自动销毁session,在web.xml文件中可以手工配置session的失效时间。
<!-- 设置Session的有效时间:以分钟为单位-->
<session-config>
<session-timeout>15</session-timeout>
</session-config>
// 主动失效
session.invalidate();
例:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setCharacterEncoding("UTF=8");
response.setContentType("text/html;charset=UTF-8");
// 获取session,如果session不存在则创建
HttpSession session = request.getSession();
// 存储
session.setAttribute("data", "hello");
// 获取session的Id
String sessionId = session.getId();
// 判断session是不是新创建的
if (session.isNew()) {
response.getWriter().print("session创建成功,session的id是:"+sessionId);
}else {
response.getWriter().print("服务器已经存在该session了,session的id是:"+sessionId);
}
}
浏览器禁用Cookie后的session处理
解决:URL重写
当检测到浏览器没有禁用cookie时,就自动不进行URL重写
方法一
// 用于对表单action和超链接的url地址进行重写
url = response.encodeURL(url);
方法二
// 用于对sendRedirect方法中的url地址进行重写
String url = response.encodeRedirectURL(request.getContextPath()+"/servlet/ListCartServlet");
response.sendRedirect(url);
表单
表单例子:
<!--form表单的action属性规定当提交表单时,向何处发送表单数据,method属性指明表单的提交方式,分为get和post,默认为get-->
<form action="${pageContext.request.contextPath}/servlet/RequestDemo03" method="post">
<!--输入文本框,SIZE表示显示长度,maxlength表示最多输入长度-->
编 号(文本框):
<input type="text" name="userid" value="NO." size="2" maxlength="2"><br>
<!--输入文本框,通过value指定其显示的默认值-->
用户名(文本框):<input type="text" name="username" value="请输入用户名"><br>
<!--密码框,其中所有输入的内容都以密文的形式显示-->
密 码(密码框):
<!-- 表示的是一个空格-->
<input type="password" name="userpass" value="请输入密码"><br>
<!--单选按钮,通过checked指定默认选中,名称必须一样,其中value为真正需要的内容-->
性 别(单选框):
<input type="radio" name="sex" value="男" checked>男
<input type="radio" name="sex" value="女">女<br>
<!--下拉列表框,通过<option>元素指定下拉的选项-->
部 门(下拉框):
<select name="dept">
<option value="技术部">技术部</option>
<option value="销售部" SELECTED>销售部</option>
<option value="财务部">财务部</option>
</select><br>
<!--复选框,可以同时选择多个选项,名称必须一样,其中value为真正需要的内容-->
兴 趣(复选框):
<input type="checkbox" name="inst" value="唱歌">唱歌
<input type="checkbox" name="inst" value="游泳">游泳
<input type="checkbox" name="inst" value="跳舞">跳舞
<input type="checkbox" name="inst" value="编程" checked>编程
<input type="checkbox" name="inst" value="上网">上网
<br>
<!--大文本输入框,宽度为34列,高度为5行-->
说 明(文本域):
<textarea name="note" cols="34" rows="5">
</textarea>
<br>
<!--隐藏域,在页面上无法看到,专门用来传递参数或者保存参数-->
<input type="hidden" name="hiddenField" value="hiddenvalue"/>
<!--提交表单按钮,当点击提交后,所有填写的表单内容都会被传输到服务器端-->
<input type="submit" value="提交(提交按钮)">
<!--重置表单按钮,当点击重置后,所有表单恢复原始显示内容-->
<input type="reset" value="重置(重置按钮)">
</form>
<!--表单结束-->
处理表单Servlet例子:
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//客户端是以UTF-8编码提交表单数据的,所以需要设置服务器端以UTF-8的编码进行接收,否则对于中文数据就会产生乱码
request.setCharacterEncoding("UTF-8");
/**
* 编 号(文本框):
<input type="text" name="userid" value="NO." size="2" maxlength="2">
*/
String userid = request.getParameter("userid");//获取填写的编号,userid是文本框的名字,<input type="text" name="userid">
/**
* 用户名(文本框):<input type="text" name="username" value="请输入用户名">
*/
String username = request.getParameter("username");//获取填写的用户名
/**
* 密 码(密码框):<input type="password" name="userpass" value="请输入密码">
*/
String userpass = request.getParameter("userpass");//获取填写的密码
String sex = request.getParameter("sex");//获取选中的性别
String dept = request.getParameter("dept");//获取选中的部门
//获取选中的兴趣,因为可以选中多个值,所以获取到的值是一个字符串数组,因此需要使用getParameterValues方法来获取
String[] insts = request.getParameterValues("inst");
String note = request.getParameter("note");//获取填写的说明信息
String hiddenField = request.getParameter("hiddenField");//获取隐藏域的内容
String instStr="";
/**
* 获取数组数据的技巧,可以避免insts数组为null时引发的空指针异常错误!
*/
for (int i = 0; insts!=null && i < insts.length; i++) {
if (i == insts.length-1) {
instStr+=insts[I];
}else {
instStr+=insts[i]+",";
}
}
String htmlStr = "<table>" +
"<tr><td>填写的编号:</td><td>{0}</td></tr>" +
"<tr><td>填写的用户名:</td><td>{1}</td></tr>" +
"<tr><td>填写的密码:</td><td>{2}</td></tr>" +
"<tr><td>选中的性别:</td><td>{3}</td></tr>" +
"<tr><td>选中的部门:</td><td>{4}</td></tr>" +
"<tr><td>选中的兴趣:</td><td>{5}</td></tr>" +
"<tr><td>填写的说明:</td><td>{6}</td></tr>" +
"<tr><td>隐藏域的内容:</td><td>{7}</td></tr>" +
"</table>";
htmlStr = MessageFormat.format(htmlStr, userid,username,userpass,sex,dept,instStr,note,hiddenField);
response.setCharacterEncoding("UTF-8");//设置服务器端以UTF-8编码输出数据到客户端
response.setContentType("text/html;charset=UTF-8");//设置客户端浏览器以UTF-8编码解析数据
response.getWriter().write(htmlStr);//输出htmlStr里面的内容到客户端浏览器显示
}
避免表单重复提交
出现问题
1.网络卡顿
2.刷新后在弹框中点击提交按钮
3.提交后再回到当前页面再点提交
解决1(2、3不能解决):
1. js
<script type="text/javascript">
// 表单是否已经提交标识,默认为false
var isCommitted = false;
function dosubmit(){
if(isCommitted==false){
// 提交表单后,将表单是否已经提交标识设置为true
isCommitted = true;
// 返回true让表单正常提交
return true;
}else{
return false;
}
}
</script>
2. js
<script type="text/javascript">
function dosubmit(){
// 获取表单提交按钮
var btnSubmit = document.getElementById("submit");
// 将表单提交按钮设置为不可用,这样就可以避免用户再次点击提交按钮
btnSubmit.disabled= "disabled";
// 返回true让表单可以正常提交
return true;
}
</script>
完美解决:session
在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),保存在Session中。然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
在下列情况下,服务器程序将拒绝处理用户提交的表单请求:
存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。
当前用户的Session中不存在Token(令牌)。
用户提交的表单数据中没有Token(令牌)。
1.servlet
// 创建令牌
String token = TokenProccessor.getInstance().makeToken();
// session保存token(令牌)
request.getSession().setAttribute("token", token);
// 跳转到form.jsp页面
request.getRequestDispatcher("/form.jsp").forward(request, response);
2.form.jsp
<input type="hidden" name="token" value="${token}"/>
3.servlet
boolean b = isRepeatSubmit(request);//判断用户是否是重复提交
if(b==true){
System.out.println("重复提交");
return;
}
request.getSession().removeAttribute("token");//移除session中的token
/**
* 判断客户端提交上来的令牌和服务器端生成的令牌是否一致
* @param request
* @return
* true 用户重复提交了表单
* false 用户没有重复提交表单
*/
private boolean isRepeatSubmit(HttpServletRequest request) {
String client_token = request.getParameter("token");
//1、如果用户提交的表单数据中没有token,则用户是重复提交了表单
if(client_token==null){
return true;
}
//取出存储在Session中的token
String server_token = (String) request.getSession().getAttribute("token");
//2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单
if(server_token==null){
return true;
}
//3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单
if(!client_token.equals(server_token)){
return true;
}
return false;
}
4.创建Token类
public class TokenProccessor {
/*
*单例设计模式(保证类的对象在内存中只有一个)
*1、把类的构造函数私有
*2、自己创建一个类的对象
*3、对外提供一个公共的方法,返回类的对象
*/
private TokenProccessor(){}
private static final TokenProccessor instance = new TokenProccessor();
/**
* 返回类的对象
* @return
*/
public static TokenProccessor getInstance(){
return instance;
}
/**
* 生成Token
* Token:Nv6RRuGEVvmGjB+jimI/gw==
* @return
*/
public String makeToken(){ //checkException
// 7346734837483 834u938493493849384 43434384
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
//数据指纹 128位长 16个字节 md5
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] = md.digest(token.getBytes());
//base64编码--任意二进制编码明文字符 adfsdfsdfsf
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
3. jsp基础知识点
JSP(Java Server Pages)
html只能为用户提供静态数据,而jsp可以为用户提供动态数据(允许在页面中嵌套java代码)。
注意:在比较正规的开发中,jsp页面是不允许出现java代码的。
JSP、Servlet都可以用于开发动态web资源。
由于2者各自的特点 加上 显示与数据分离原则, servlet只用来负责响应请求处理数据并传给jsp,jsp则只用来负责显示数据。
浏览器向服务器发请求访问的资源本质都是Servlet。
当访问一个index.jsp页面时,服务器会将index.jsp翻译成一个index_jsp.class(内容在_jspService方法中),在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp目录下可以看到index_jsp.class的源代码文件index_jsp.java。
该类继承自HttpJspBase,HttpJspBase继承自HttpServlet。
标签则换成out.write(" <head>\r\n");,嵌套的java则原封不动。
请求流程
1.客户端发送请求
2.WEB容器接收请求并处理,找到需要执行的*.jsp文件,转换变为*.java文件,编译为*.class文件
3.服务器执行*.class文件(如果.jsp文件有修改则需重新编译,否则再次访问时使用该class文件)
例
<html>
<head>
<title>第一个 JSP 程序</title>
</head>
<body>
<%
out.println("Hello World!");
%>
</body>
</html>
- 基础语法
运算符
后缀 () [] . (点运算符) 左到右
一元 ++ - - ! ~ 右到左
可乘性 * / % 左到右
可加性 + - 左到右
移位 >> >>> << 左到右
关系 > >= < <= 左到右
相等/不等 == != 左到右
位与 & 左到右
位异或 ^ 左到右
位或 | 左到右
逻辑与 && 左到右
逻辑或 || 左到右
条件判断 ?: 右到左
赋值 = += -= *= /= %= >>= <<= &= ^= |= 右到左
逗号 , 左到右
字面量
布尔值(boolean):true 和 false;
整型(int):与 Java 中的一样;
浮点型(float):与 Java 中的一样;
字符串(string):以单引号或双引号开始和结束;
Null:null
语句
<% if (day == 1 | day == 7) { %>
<p>今天是周末</p>
<% } else { %>
<p>今天不是周末</p>
<% } %>
<%
switch(day) {
case 0:
out.println("星期天");
break;
case 1:
out.println("星期一");
break;
case 2:
out.println("星期二");
break;
case 3:
out.println("星期三");
break;
case 4:
out.println("星期四");
break;
case 5:
out.println("星期五");
break;
default:
out.println("星期六");
}
%>
<%for ( fontSize = 1; fontSize <= 3; fontSize++){ %>
<font color="green" size="<%= fontSize %>">
hello
</font><br />
<%}%>
<%while ( fontSize <= 3){ %>
<font color="green" size="<%= fontSize %>">
world
</font><br />
<%fontSize++;%>
<%}%>
在JSP中,所有的JAVA语句都可以使用。
JSP模版元素
JSP页面中的HTML内容(定义了页面的结构和外观)。
JSP表达式
用于将数据输出到页面(表达式的值会被转化成String,不能使用分号来结束)
<%= 变量或表达式 %>
解析为java类时=》将表达式的值转为字符串,out.print(值)
<%= 表达式 %>
等价以下
<jsp:expression>
表达式
</jsp:expression>
JSP脚本片断
<%
多行java代码 (定义变量、编写语句,不能定义方法)
每执行语句后面必须用分号结束
不能是html标签
%>
解析为java类时=》直接原封不动
多个脚本片断中的代码可以相互访问
<%
for (int i=1; i<5; i++) {
%>
<H1>hello</H1>
<%
}
%>
<% JAVA代码片段 %>
等价以下
<jsp:scriptlet>
代码片段
</jsp:scriptlet>
例:
在网页上打印文本
<%
out.println("IP address is " + request.getRemoteAddr());
%>
JSP声明
<%!
java代码
%>
用于定义静态代码块、成员变量和方法。不能使用隐式对象(8)
解析=》JSP页面中编写的所有代码,默认会翻译到servlet的service方法中, 而jsp声明中的java代码被翻译到_jspService方法的外面。
<%! declaration; [ declaration; ]+ ... %>
等价以下
<jsp:declaration>
代码片段
</jsp:declaration>
例:
<%! int i = 0; %>
<%! int a, b, c; %>
<%! Circle a = new Circle(2.0); %>
JSP注释
查看源文件时HTML注释可以被看到,JAVA注释和JSP注释则看不到
1、显式注释(HTML) <!-- 注释内容 -->
2、隐式注释(JAVA) //、/*……*/
3、独有注释(JSP) <%-- 注释内容 --%>
- 内置对象
9个内置对象
PageContext pageContext;
HttpSession session;
ServletContext application;
ServletConfig config;
JspWriter out;
Object page = this;
HttpServletRequest request;
HttpServletResponse response;
Exception exception;
使用
<%
pageContext对象(最常用)
不仅封装了对其它8大隐式对象的引用,还用于设置/获取值
getException方法返回exception隐式对象
getPage方法返回page隐式对象
getRequest方法返回request隐式对象
getResponse方法返回response隐式对象
getServletConfig方法返回config隐式对象
getServletContext方法返回application隐式对象
getSession方法返回session隐式对象
getOut方法返回out隐式对象
// pageContext设值(本页内有效)
pageContext.setAttribute("name", "pageContext对象");
// 向其他域中设值(PageContext.APPLICATION_SCOPE、PageContext.SESSION_SCOPE、PageContext.REQUEST_SCOPE、PageContext.PAGE_SCOPE )
pageContext.setAttribute("name","你好",PageContext.SESSION_SCOPE);
// pageContext取值
out.print(pageContext.getAttribute("name")+"<br/>")
// 从其他域中取值
String name = (String)pageContext.getAttribute("name",PageContext.SESSION_SCOPE);
// 删除
pageContext.removeAttribute("name");
// 查找(page→request→session→application,都没找到则返回null)
String name= (String)pageContext.findAttribute("name");
// 寻找顺序同上,找不到时返回空字符串
${name},
// 跳转(简化request跳转)不常用,一般使用<jsp:forward>跳转
pageContext.forward("/pageContextDemo05.jsp");
// 引入(不常用,一般使用jsp:include)
<% pageContext.include("/jspfragments/head.jsp"); %>
request对象
// 使用request对象
out.print(request.getContextPath()+"<br/>");
// 设值
request.setAttribute("name", "hello");
session对象
// 设值
session.setAttribute("name", "值");
// 取值
out.print(session.getAttribute("name")+"<br/>");
application对象
// 设值
application.setAttribute("name", "application对象");
// 取值
out.print(application.getAttribute("name")+"<br/>");
out对象
用于向浏览器显示文本数据
out对象的类型为JspWriter(缓存功能),设置page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。
只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
1.设置page指令的buffer属性关闭了out对象的缓存功能
2.out对象的缓冲区已满
3.整个JSP页面结束
// 使用out对象
out.print("Hello Jsp"+"<br/>");
page对象(几乎不用)
表示当前jsp页面
// 使用page对象
out.print("服务器调用index.jsp页面时翻译成的类的名字是:"+page.getClass()+"<br/>");
// 使用config对象
out.print("处理请求的Servlet的名字是:"+config.getServletName()+"<br/>");
// 使用response对象
out.print(response.getContentType()+"<br/>");
%>
作用域
4种范围
1.当前页(pageContext)
只作用于当前页面(其他页面无法获取)
2.一次服务器请求(request)
一个页面经服务器跳转后的页面也可以获取。
3.一次会话(session)
打开浏览器直到关闭
4.上下文中(application)
在整个服务器上设置的属性,所有人都可以访问
// 设值
.setAttribute("name", "对象");
// 取值
.getAttribute("name");
// 删除
.removeAttribute("name");
- 指令
并不产生任何输出,只是告诉引擎如何处理JSP页面中的其余部分
格式
<%@ 指令 属性名="值" %>
3种:
page指令 (jsp页面相关属性,如:编码)
Include指令 (包含其他文件)
taglib指令 (引入标签库的定义,可以是自定义标签)
page指令
用于定义JSP页面的各种属性,作用整个JSP页面(无论位置,但建议页面最上的位置)
<%@ page
[ language="java" ] 定义JSP页面所用的脚本语言,默认是Java
[ extends="package.class" ] 指定servlet从哪一个类继承
[ import="{package.class | package.*}, ..." ] 导入要使用的Java类
[ session="true | false" ] 指定JSP页面是否使用session
[ buffer="none | 8kb | sizekb" ] 指定out对象使用缓冲区的大小
[ autoFlush="true | false" ] 控制out对象的 缓存区
[ isThreadSafe="true | false" ] 指定对JSP页面的访问是否为线程安全
[ info="text" ] 定义JSP页面的描述信息
[ errorPage="relative_url" ] 指定当JSP页面发生异常时需要转向的错误处理页面
[ isErrorPage="true | false" ] 指定当前页面是否可以作为另一个JSP页面的错误处理页面
[ contentType="mimeType [ ;charset=characterSet ]" | "text/html ; charset=ISO-8859-1" ] 指定当前JSP页面的MIME类型和字符编码
[ pageEncoding="characterSet | ISO-8859-1" ] 编码
[ isELIgnored="true | false" ] 指定是否执行EL表达式
%>
例:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.util.Date"%>
<%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%>
page指令的import属性
在Jsp页面中,Jsp引擎会自动导入下面的包
java.lang.*
javax.servlet.*
javax.servlet.jsp.*
javax.servlet.http.*
<%@ page import="java.util.*,java.io.*,java.sql.*"%>
page指令的pageEncoding、errorPage、isErrorPage属性
errorPage:值必须使用相对路径。如果以“/”开头,表示相对于当前Web应用程序的根目录(注意不是站点根目录)。
isErrorPage:显式声明页面为错误页面。exception.getMessage()获取错误信息
<%@ page language="java" contentType="text/html; charset=UTF-8" import="java.util.*" errorPage="/ErrorPage/error.jsp" pageEncoding="UTF-8"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isErrorPage="true"%>
web.xml指定整个网站出错时的错误页
<error-page>
<error-code>404</error-code>指定错误的状态码
<exception-type>java.lang.ArithmeticException</exception-type>
<exception-type>指定异常类的完全限定名(可不写)
<location>/ErrorPage/404Error.jsp</location>指定状态码下的错误处理页面
</error-page>
JSP页面的errorPage属性优先级更高
注意:
如果错误页面大小比较小,在IE浏览器下是无法跳转到错误页面的。(尽量页面大小大于1024bytes)
include指令
2种形式:
@include指令
<jsp:include>指令
@include指令
<%@include file="/jspfragments/head.jspf" %>
静态引入,直接内容替换导入。(注意不能声名两个同名变量)
解析=》将两个jsp转成一个Servlet
被引用的文件:
可以使用任意的扩展名(建议为.jspf),都会按照jsp页面处理
jsp:include指令
动态包含,对jsp文件先处理再导入(其他文件则直接替换内容)。
对.jspf文件中的内容作为纯文本处理,不执行jsp指令。解决:
方法1.修改web.xml;方式2.修改tomcat服务器的web.xml
<!-- 让jspf扩展名同样成为JSP Servlet处理的文件。 -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jspf</url-pattern>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
引入标签库的定义,可以是自定义标签
<%@ taglib uri="uri" prefix="prefixOfTag" %>
等价以下
<jsp:directive.taglib uri="uri" prefix="prefixOfTag" />
- JSP标签
用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护
<jsp:动作名 属性名="属性值" />
动作名
include 用于包含静态/动态文件。
useBean 寻找和初始化一个JavaBean组件
setProperty 设置 JavaBean组件的值
getProperty 将 JavaBean组件的值插入到 output中
forward 从一个JSP文件向另一个文件传递一个包含用户请求的request对象
plugin 用于在生成的HTML页面中包含Applet和JavaBean对象
element 动态创建一个XML元素
attribute 定义动态创建的XML元素的属性
body 定义动态创建的XML元素的主体
text 用于封装模板数据
param
属性
id属性 唯一标识
scope属性 page, request, session, 和 application
<jsp:include>标签
<jsp:include page="relativeURL | <%=expression%>" flush="true|false" />
动态引入
解析=》会被转成2个Servlet
include指令:是在JSP文件被转换成Servlet时引入文件,
jsp:include:在页面被请求时引入文件
flush:定义在包含资源前是否刷新缓存区
例:
<jsp:include page="/jspfragments/head.jsp"/>
<jsp:forward>标签 (跳到另一页)
<jsp:forward page="relativeURL | <%=expression%>" />
例:
<jsp:forward page="/forwarddemo02.jsp"/>
<jsp:param>标签
<jsp:forward>标签 和 <jsp:include>标签 的子标签
<jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
例:
<jsp:include page="/jspfragments/Inc.jsp">
<jsp:param name="parm1" value="hello" />
<jsp:param name="parm2" value="gacl" />
</jsp:include>
<jsp:plugin>标签
例:
<jsp:plugin type="applet" codebase="dirname" code="MyApplet.class"
width="60" height="80">
<jsp:param name="fontcolor" value="red" />
<jsp:param name="background" value="black" />
<jsp:fallback>
Unable to initialize Java Plugin
</jsp:fallback>
</jsp:plugin>
<jsp:useBean>标签
例:
<jsp:useBean id="test" class="com.runoob.main.TestBean" />
<jsp:setProperty name="test"
property="message"
value="输出..." />
<jsp:getProperty name="test" property="message" />
4. JavaBean
JavaBean(一个遵循特定写法的Java类):
1.必须具有一个无参的构造函数
2.属性必须私有化,且通过public类型的方法(遵守一定的命名规范)对外。
JavaBean可以有多个属性,属性可以是任意类型。
每个属性通常都需要具有相应的setter(属性修改器,必须以小写的set前缀开始,后跟属性名-第一个字母大写)、 getter方法(属性访问器,必须以小写的get前缀开始,后跟属性名-第一个字母大写)。只有set方法的属性:只写属性。只有get方法的属性:只读属性。
例:
/**
* Person类
*/
public class Person {
//------------------Person类封装的私有属性---------------------------------------
// 姓名 String类型
private String name;
// 年龄 int类型
private int age;
//是否已婚 boolean类型
private boolean married;
//------------------Person类的无参数构造方法---------------------------------------
/**
* 无参数构造方法
*/
public Person() {
}
//------------------Person类对外提供的用于访问私有属性的public方法---------------------------------------
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isMarried() {
return married;
}
public void setMarried(boolean married) {
this.married = married;
}
}
使用
在JSP页面中:
<jsp:useBean>标签
用于查找JavaBean组件,不存在则创建。
<jsp:setProperty>标签
用于设置一个JavaBean组件的属性。
<jsp:getProperty>标签
用于获取一个JavaBean组件的属性。
<jsp:useBean>标签
查找JavaBean组件,不存在则创建
<jsp:useBean id="beanName" class="package.class" scope="page|request|session|application"/>
"id" :实例对象名
"class":必须带有包名的完整类名
"scope":作用域范围,默认值是page。
例:
<jsp:useBean id="person" class="com.cx.Person" scope="page"/>
<% person.setName("hello"); %>
<%=person.getName()%>
<jsp:setProperty>标签
<jsp:setProperty name="beanName" property="propertyName" value="string字符串"/>
<jsp:setProperty name="beanName" property="propertyName" value="<%= expression %>" />
<jsp:setProperty name="beanName" property="propertyName" param="parameterName"/>
<jsp:setProperty name="beanName" property= "*" />
例:
<jsp:useBean id="person" class="com.cx.Person" scope="page"/>
可以将字符串转为8种基础数据类型,不能转换复合数据类型(如:Date)
<jsp:setProperty property="name" name="person" value="hello"/>
将指定param_name参数的值,为属性赋值
<jsp:setProperty property="name" name="person" param="param_name"/>
将所有参数的值,为属性赋值
<jsp:setProperty property="*" name="person"/>
<%=person.getName()%>
<jsp:getProperty>标签
<jsp:getProperty name="beanInstanceName" property="PropertyName" />
例:
<jsp:getProperty property="name" name="person"/>
5. 架构模式
JavaBean+JSP架构模式
适合小型业务
JavaBean负责封装数据(用于保存和获取)。
JSP负责处理请求和显示数据。
JavaBean+JSP+Servlet架构模式
MVC模式
Model(模型层)
JavaBean负责封装数据(用于保存和获取和处理数据)。
View(视图层)
JSP负责显示数据。
Controller(控制器层)
Servlet负责让JavaBean处理数据,并将结果传给jsp。
缺点:
1.控制层复杂
2.从获取请求参数到给模型赋值比较繁琐,可交由框架处理
3.跳转至其他页面和传递模型 严重依赖Servlet API
4.javaBean复杂,可以为模型层、业务逻辑层、持久层