要知道servlet的使用需要了解servlet的工作基础
什么是servlet:sun公司制订的一种用来扩展web服务器功能的组件规范。
servlet之前是使用cgi(common gateway interface),收到请求会调用cgi,后面servlet就因运而生,是一种更好的技术,需要符合一定的组件规范,即实现部分软件模块,组件需要部署到容器的内部,servlet本身就是一种容器。
下面是基于浏览器和客户端的请求详细图解:
编写一个简单servlet程序,在Eclipse中新建一个web工程:
首先需要在src目录下新建一个类继承HttpServlet,可以重写HttpServlet中的service方法实现相应的功能,还需要在WEB-INF目录下找到web.xml,在其中配置
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.heying.web.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
Java code:
public class HelloServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
@Override
public void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.print("hello servlet !<br>");
out.print("i am a programmer !<br>");
out.close();
}
}
这个程序使用的是PrintWriter 来输出一个页面数据返回类型是text/html
这边是一个简单的servlet程序,需要完成复杂的功能还需要后面继续学习
为了更好的了解servlet需要知道几个简单知识点:
什么是Http协议:由w3c制订的一种网络应用层协议,规定了浏览器与web服务器之间如何通信以及相应的数据格式。目前已经出现Https协议(加密的)。
通信步骤大致分为:
1.浏览器建立与服务器之间的连接。
2.浏览器将请求数据打包并发送。
3.服务器将响应数据打包并发送。
4.服务器立即关闭连接。
一次请求一次连接,高效
数据格式:
请求行:请求方式 请求资源路径 协议类型和版本
消息头:是一些键值对,表示特定的含义,浏览器与服务器之间都可以发送。比如,浏览器可以发送一个”User-Agent”消息头,告诉服务器,浏览器的类型和版本。
实体内容:只有当请求方式为post的时候,实体内容才有数据(请求参数),如果请求方式是get,请求参数会添加到请求资源路径的后面。
状态行: 协议及版本 状态码 状态描述,比如404 500等错误代码
get和post请求:
get请求:
1.会将请求参数添加到请求资源路径的后面,因为请求行最多只能存放2k左右的数据,所以,get请求只能发送少量的请求参数。
2.会将请求参数显示在浏览器地址栏,不安全比如,路由器会记录访问地址。
post请求:
设置了表单的method=”post”。
1.将请求参数放到实体内容里面,所以,可以提交大量的数据给服务器。
2.不会将请求参数显示在浏览器地址栏,相对安全(不会加密,对于敏感数据,需要加密)。
输出中文:
java语言使用unicode字符集来保存字符。
编码:将unicode字符集对应的字节数组转换成某种本地字符集(gbk,utf-8等等)对应的字节数组。
解码:某种本地字符集(gbk,utf-8等等)对应的字节数组转换成unicode字符集对应的字节数组。
路径问题:
相对路径
不以”/”开头的路径。
绝对路径
以”/”开头的路径。
不要直接写绝对路径,要使用以下方法获得应用名:request.getContextPath()
cookie技术:
服务器临时保存在浏览器端的少量的数据。
当浏览器向服务器发送请求时,服务器会将少量的数据以set-cookie消息头的方式发送给浏览器,浏览器会将这些数据临时保存下来;当浏览器再次访问服务器时,会将之前保存的数据以cookie消息头的方式发送给服务器。
使用new Cookie(String name,String value)来设置 response.addCookie(…);
几个简单的知识先了解后,来简单说明下servlet的工作原理和过程servlet的生命周期:
1. 实例化
器收到请求之后,创建servlet对象,需要给这个servlet配置参数。该参数是一个大于等于0的整数。值越小,优先级越高(先被创建)
2. 容器在创建好servlet对象之后,会立即调用该对象的init方法,初始化方法(init)只会执行一次。一般情况下,我们不用写init方法,因为GenericServlet已经提供了init方法的实现
实现过程:
将容器传递进来的ServletConfig对象保存下来,并且提供了一个getServletConfig方法来获得这个对象。
3. 初始化参数
company
xxxx
ServletConfig.getInitParameter(“company”);
4. 就绪状态会依据请求类型分别调用doGet或者doPost方法,可以
override HttpServlet的service方法 或 override HttpServlet的doGet/doPost
5.销毁
容器在删除servlet对象之前,会调用该对象的destroy方法,destroy方法只会执行1次,一般不需要写自己的destroy方法,GenericServlet已经提供了实现。
引入jsp技术
jsp:sun公司制订的一种服务器端动态页面技术规范。
因为使用servlet,虽然也可以生成动态页面,但是,过于繁琐(需要使用out.println语句),并且难以维护(修改页面,就需要修改java源代码),所以,sun公司才制订了jsp规范。
jsp其实就是一个以”.jsp”为后缀的文件,该文件的内容主要是html和少量的java代码。jsp文件会被容器转换成一个servlet然后执行,在tomcat的容器中有个work目录下就是jsp转换为servlet的临时目录,页面被编译为printwriter中输出。
jsp语法:
<% java代码 %>
<%= java表达式 %>
隐含对象:
session ,pagecontext,request,response等
导包:
<%@page import=”java.util.*”%>
<%@page import=”java.util.,java.text.“%>
servlet容器如何处理请求资源路径:
精确匹配:
要求的值必须是/abc.bcd。
通配符匹配:
使用”*”匹配0个或者多个字符。
/*
后缀匹配:
*.do
下面是以前我写的交友网站为例:
在web.xml使用*.do 后缀模糊匹配多个类是请求:checkcode是验证码的servlet
<servlet>
<servlet-name>ActionServlet</servlet-name>
<servlet-class>web.ActionServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>CheckcodeServlet</servlet-name>
<servlet-class>web.CheckcodeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ActionServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CheckcodeServlet</servlet-name>
<url-pattern>/checkcode</url-pattern>
</servlet-mapping>
截取uri请求地址路径:
String uri = request.getRequestURI();
String action = uri.substring(uri.lastIndexOf("/")+1,uri.lastIndexOf("."));
在jsp页面的form表单的action使用不同的请求地址:
把页面数据绑定到request上:
request.setAttribute(..,..);
绑定数据到页面
request.getRequestDispatcher("login.jsp")
.forward(request, response);
比如需要的使用删除后刷新,需要使用到重定向:
response.sendRedirect("login.jsp");
验证码页面代码:
<img id="img1" border="1" src="checkcode" onclick="this.src='checkcode?' + Math.random();"/>
<a href="javascript:;" onclick="document.getElementById('img1').src='checkcode?'+ Math.random();">看不清,换一个</a>
java:
package web;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class CheckcodeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
* 一、绘图
*/
/*
* step1,创建一个内存映像对象(画布) BufferedImage(宽度,高度,类型)
*/
BufferedImage image = new BufferedImage(80, 30,
BufferedImage.TYPE_INT_RGB);
/*
* step2,获得一个画笔
*/
Graphics g = image.getGraphics();
/*
* step3,给笔设置颜色
*/
Random r = new Random();
g.setColor(new Color(255, 255, 255));
/*
* step4,给画布设置背景颜色 fillRect(x,y,width,height)
*/
g.fillRect(0, 0, 80, 30);
/*
* step5,绘图
*/
g.setColor(new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255)));
// Font(字体,风格,大小)
g.setFont(new Font(null, Font.ITALIC, 22));
String number = getNumber(5);
// 将number绑订到session对象上
HttpSession session = request.getSession();
session.setAttribute("number", number);
// drawString(String,x,y) x,y是左下角的坐标
g.drawString(number, 2, 23);
// step6,加一些干扰线
for (int i = 0; i < 12; i++) {
g.drawLine(r.nextInt(80), r.nextInt(30), r.nextInt(80), r
.nextInt(30));
}
/*
* 二、将图片压缩并发送给浏览器
*/
// 设置content-type消息头,告诉
// 浏览器返回的是图片
response.setContentType("image/jpeg");
// 一定要获得字节输出流
OutputStream ops = response.getOutputStream();
// write方法会对原始图片(image)按照
// 指定的压缩算法(jpeg)进行压缩,并且
// 将压缩之后的数据输出到指定的流(ops)。
javax.imageio.ImageIO.write(image, "jpeg", ops);
ops.close();
}
/*
* 生成一个验证码,该验证码由"A~Z","0~9"中 随机选取5个字符组成
*/
private String getNumber(int size) {
String rs = "";
String strs = "ABCDEFGHIJKLMNOPQ" + "RSTUVWXYZ0123456789";
Random r = new Random();
for (int i = 0; i < size; i++) {
rs += strs.charAt(r.nextInt(strs.length()));
}
return rs;
}
}