Java Web学习笔记 3 深入Servlet技术

时间:2023-02-24 19:17:05

第3章 深入Servlet技术
请求-响应模式就是典型的Web应用程序访问过程,Java Web应用程序中,处理请求并发送响应的过程是由一种叫做Servlet的程序来完成的。
请求request,响应response,与HTTP协议
Telnet演示HTTP协议 默认telnet关闭的,控制面板中,program and feathers,找到telnet client进行开启。
GET方式查询:常用来查询信息 HTTP头数据: User-Ageent:Mozilla/4.0(...)   浏览器信息 Accept:text/html; */*              浏览器支持的格式 cookie: account-Helloween       记录用户当前的状态 Referer: http://www.baidu.com 指从哪个页面单击链接进入的
POST方式提交数据 GET提交数据不能超过256字符,POST提交,数据不在浏览器地址中显示,常用来提交表单数据
其他访问方式 HEAD,DELETE,TRACE,PUT,OPTIONS
Servlet概述 Java Web应用程序中所有的请求-响应都是Servlet完成的,没有main之类的方法,当用户访问服务器的时候,Tomcat通过调用Servlet的某些方法完成整个处理过程的。
Servlet工作流程 HttpServeltRequest/HttpServletResponse Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
Servlet接口 GET/POST/HEAD/PUT/DELETE/TRACE 一般为 doGet()/doPost() .../getLastModified(request)返回文档的最后修改时间
Java Web目录结构 Web程序部署在Tomcat的/webapps下面,用 http://localhost:8080/web1
编写Servlet javax.servlet.* javax.servlet.http.*  一般直接继承HttpServlet,覆盖方法即可,一般只覆盖doGet(),doPost()
3.3.1 实现Servlet
编写Web Project,FirstServlet.java,覆盖常用三个方法 本书使用的是java EE5,新建项目时需要注意 新建web Project-> 新建servlet, FirstServlet.java
/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*
* GET方式访问页面执行该函数 执行doGet之前会执行getLastModified,如果发现返回的数值与上次访问是相同,
* 则认为文档没有更新,浏览器采用缓存而不执行,如果返回 -1,则认为最新,总是执行该函数
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

this.log("执行doGet方法..." );// 控制台日志输出信息
this.execute(request , response );// 处理doGet
}

/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*
* 以post方式访问页面时执行该函数,执行前不会调用getLastModified
*/
public void doPost(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

this.log("执行doPost方法" );
this.execute(request , response );
}

@Override
protected long getLastModified(HttpServletRequest req) {
// TODO Auto-generated method stub
this.log("执行 getLastModified 方法" );
return -1;
}

// 执行方法
private void execute(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding( "UTF-8");
request.setCharacterEncoding( "UTF-8");

String requestURI = request.getRequestURI();
String method = request.getMethod();
String param = request.getParameter("param" );// 客户端提交的参数 param值

response.setContentType( "text/html");// 文档类型为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.println( " 以" + method + " 方式访问该页面。取到的param参数为:" + param + "<br/>" );

out.println( " <form action='"
+ requestURI
+ "' method='get'> <input type='text' name='param' value='param string'><input type='submit' value='以GET方式查询页面"
+ requestURI + "'> </form>" );
out.println( " <form action='"
+ requestURI
+ "' method='post'> <input type='text' name='param' value='param string'><input type='submit' value='以POST方式提交页面 "
+ requestURI + "'></form>" );

//客户端浏览器读取该文档的更新时间
out.println( " <script>document.write('本页面最后更新时间: ' + docment.lastModified); </script>" );
out.println( " </BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}

3.3.2 配置<Servlet>
首先名称及类名:
<servlet-name> FirstServlet</servlet-name >
<servlet-class >servlet.FirstServlet </servlet-class>

<init-param>
<param-name >message </param-name>
<param-value >welcome to FisrtServlet </param-value>
</init-param >
<init-param >
<param-name >encoding </param-name>
<param-value >utf-8</ param-value>
</init-param >
配置一个初始化参数
< load-on-startup>1 </load-on-startup>
配置Servlet的加载方式。0和1,1启动加载,否则,Tomcat会在有人第一次请求加载
<servlet-mapping>
<servlet-name >FirstServlet </servlet-name>
<url-pattern >/ servlet/FirstServlet</url-pattern >
</servlet-mapping >
<url-pattern > 配置该Servlet的访问方式:这里即http://localhost:8080/servlet /servlet/FirstServlet 如果配置为/servlet/FirstServlet.* 使用http://localhost:8080/servlet /servlet/FirstServlet.XXX访问 通配符试了好像不行,还是支持多个映射,把需要的映射加进去吧
一个完整的servlet包括servlet类,<servlet>配置,<servlet-mapping>配置。利用myeclipse向导自动完成配置。
???部署到Tomcat6.0系统,然后启动,发现超时,可以使用: 部署的时候出现Server Tomcat v6.0 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor? 我们找到当前工程的workplace目录,然后按下面的操作: 找到workspace\.metadata\.plugins\org.eclipse.wst.server.core\servers.xml文件。 把其中的start-timeout="45" 改为  start-timeout="100" 或者更长,根据不同同学的工程大小来设置。 最后重启eclipse就可以了。
3.4 请求与响应
获取request变量 客户端浏览器发出的请求被封装HttpServletRequest对象,包含所有的信息。 在servlet项目中新建servlet, RequestServlet.java:
public class RequestServlet extends HttpServlet {

/**
* Constructor of the object.
*/
public RequestServlet() {
super();
}

/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}

// 返回客户端浏览器接受的文件类型
private String getAccept(String accept) {
StringBuffer buffer = new StringBuffer();
if (accept .contains("image/gif"))
buffer.append( "GIF文件,");
if (accept .contains("image/x-xbitmap"))
buffer.append( "BMP文件,");
if (accept .contains("image/jpeg"))
buffer.append( "JPG文件,");
if (accept.contains("application/vnd.ms-execel" ))
buffer.append( "EXCEL文件," );
if (accept.contains("application/vnd.ms-powerpoint" ))
buffer.append( "PPT文件,");
if (accept .contains("application/vnd.msword"))
buffer.append( "Word文件," );
return buffer .toString().replaceAll(", $", "");
}

// 返回客户端的语言环境
private String getLocale(Locale locale) {
if (Locale.SIMPLIFIED_CHINESE.equals(locale))
return "简体中文" ;
if (Locale.TRADITIONAL_CHINESE.equals(locale))
return "繁体中文" ;
if (Locale.ENGLISH.equals(locale))
return "英文" ;
if (Locale.JAPANESE.equals(locale))
return "日文" ;
return "未知语言环境" ;
}

// 返回IP地址对应的物理地址
// private String getAddress(String ip){
// return IpUtil.getIpAddress(ip);
// }

// 返回客户端浏览器信息
private String getNavigatior(String userAgent) {
if (userAgent .indexOf("TencentTraveler") > 0)
return "腾讯浏览器" ;
if (userAgent .indexOf("Maxthon") > 0)
return "Maxthon浏览器" ;
if (userAgent .indexOf("MyIE2") > 0)
return "MyIE2浏览器" ;
if (userAgent .indexOf("Firefox") > 0)
return "Firefox浏览器" ;
if (userAgent .indexOf("MSIE") > 0)
return "IE浏览器" ;
return "未知浏览器" ;
}

// 返回客户端操作系统
private String getOS(String userAgent) {
if (userAgent .indexOf("Windows NT 5.1") > 0)
return "Windows XP" ;
if (userAgent .indexOf("Windows 98") > 0)
return "Windows 98" ;
if (userAgent .indexOf("Windows NT 5.0") > 0)
return "Windows 2000" ;
if (userAgent .indexOf("Linux") > 0)
return "Linux" ;
if (userAgent .indexOf("Unix") > 0)
return "Unix" ;
return "未知" ;
}

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

request.setCharacterEncoding( "UTF-8");
response.setCharacterEncoding( "UTF-8");
response.setContentType( "text/html");//文档类型为HTML

String authType = request .getAuthType();
String localAddr = request .getLocalAddr();//本地IP,服务器IP
String localName = request .getLocalName();//本地名称,服务器名称
int localPort = request .getLocalPort();//本地端口,Tomcat端口

Locale locale = request.getLocale(); //用户的语言环境
String contextPath = request .getContextPath();
String method = request .getMethod();//get还是post
String pathInfo = request .getPathInfo();
String pathTranslated = request.getPathTranslated();
String protocol = request.getProtocol(); //协议,这里指HTTP协议
String queryString = request.getQueryString();//查询字符串,即?后面的字符串

String remoteAddr = request .getRemoteAddr();//远程IP,客户端IP

int port = request .getRemotePort();//远程端口,客户端端口
String remoteUser = request .getRemoteUser();//远程用户
String requestedSessionId = request.getRequestedSessionId();//客户端session的ID

String requestURI = request .getRequestURI();//用户请求的URI
StringBuffer requestURL = request.getRequestURL();//用户请求的URL

String scheme = request.getScheme(); //协议头,这里为 http
String serverName = request .getServerName();//服务器名称
int serverPort = request .getServerPort();//服务器端口
String servletPath = request.getServletPath();// servlet的路径
Principal userPrincipal = request.getUserPrincipal();

String accept = request.getHeader( "accept");//浏览器支持的格式
String referer = request.getHeader("referer" );//从哪个页面单击到本页

//user-agent 包括操作系统类型、版本号、浏览器类型、版本号
String userAgent = request.getHeader("user-agent" );
String serverInfo = this.getServletContext().getServerInfo();

PrintWriter out = response.getWriter();
out.println( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println( "<HTML>");

out.println( " <HEAD><TITLE>Request Servlet</TITLE></HEAD>");
out.println( " <style>body, font, td, dic {font-size:12px; line-height:18px }</style>");
out.println( " <BODY>");

out.println( "<b>您的IP为</b>" + remoteAddr + "<b>,位于</b>:空 "
+ "<b>; 您使用</b>" + getOS(userAgent) + "<b>操作系统</b>,"
+ getNavigatior( userAgent) + "<b>,您使用</b> " + getLocale(locale)
+ "。 <br/>");

out.println( "<b>服务器IP为</b>" + localAddr + "<b>,位于</b>:空 "
+ "<b>; 服务器使用</b>" + serverPort + "<b>端口,您的浏览器使用了</b>," + port
+ "<b>端口访问本网页。</b><br/>" );

out.println( "<b>服务器软件为</b>" + serverInfo + "<b>服务器名称为</b> "
+ localName + "。<br/>" );
out.println( "<b>您的浏览器接受</b>" + getAccept(accept) + "。<br/>" );
out.println( "<b>您从</b>" + referer + "<b>访问到该页面。</br><br/>" );
out.println( "<b>使用的协议为</b>" + protocol + "。<b>URL协议头</b>" + scheme
+ ",<b>服务器名称</b>" + serverName + ",<b>您访问的URI为</b>"
+ requestURI + "。<br/>" );
out.println( "<b>该servlet的路径为</b>" + servletPath + ", <b>该servlet类名为</b>" + this.getClass().getName()
+ "。<br/>");
out.println( "<b>本应用程序在硬盘的根目录为</b>" + this.getServletContext().getRealPath("" ) + ", <b>网络的相对路径为</b>" + contextPath + "。<br/>" );
out.println( "<br/>");
out.println( "<br/><br/><a href=" + requestURI + "> 单击刷新本页面</a>" );
out.println( " </BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException
* if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
}

Java Web学习笔记 3 深入Servlet技术 结果: Java Web学习笔记 3 深入Servlet技术


3.4.2 response生成图片验证码
通过HttpServletResponese获取的PrintWrite对象只能写字符型数据。 这里使用Servlet输出图片验证码,原理: 服务器生成一个包含随机字符串的图片发给客户端,客户端提交数据时需要填写字符串作为验证。 Servlet输出图片时,需要调用getOutputStream.
IdentityServlet.java
public class IdentityServlet extends HttpServlet {

// 随机字典 不包括男人的0,O,1,I
public static final char[] CHARS = { '2', '3', '4', '5', '6' , '7' , '8' ,
'9', 'A', 'B', 'C', 'D', 'D', 'E', 'F', 'G', 'H' , 'J' , 'K' , 'L' ,
'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W' , 'X' , 'Y' , 'Z' };
public static Random random = new Random();

// 获取6位随机数
public static String getRandomstring() {
StringBuffer buffer = new StringBuffer();// 字符串缓存
for (int i = 0; i < 6; i++) {
buffer.append( CHARS[random .nextInt(CHARS. length)]);
}
return buffer .toString();
}

// 获取随机的颜色
public static Color getRandomColor() {
return new Color(random.nextInt(255), random.nextInt(255),
random.nextInt(255));
}

// 返回某颜色的反色
public static Color getReverseColor(Color c ) {
return new Color(255 - c.getRed(), 255 - c.getGreen(),
255 - c.getBlue());
}

/**
* Constructor of the object.
*/
public IdentityServlet() {
super();
}

/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

response.setContentType( "image/jpeg");// 设置输出类型

String randomString = getRandomstring();
// 放到session中
request.getSession( true).setAttribute("randomString" , randomString);

// 图片高度和宽度
int width = 100;
int height = 30;

// 随机颜色 背景色
Color color = getRandomColor();
Color reverse = getReverseColor(color);

// 创建彩色图片
BufferedImage bi = new BufferedImage(width , height,
BufferedImage. TYPE_INT_RGB);

// 获取绘图对象
Graphics2D g = bi.createGraphics();
g.setFont( new Font(Font.SANS_SERIF, Font.BOLD, 16));
g.setColor( color);
g.fillRect(0, 0, width, height); // 绘制背景
g.setColor( reverse); // 设置颜色
g.drawString( randomString, 18, 20);// 绘制随机字符
for (int i = 0, n = random.nextInt(100); i < n; i++) {
g.drawRect( random.nextInt(width ), random.nextInt(height ), 1, 1);
}
ServletOutputStream out = response.getOutputStream();
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(bi);
out.flush();
}

/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to
* post.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doPost(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

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 POST method");
out.println( " </BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException
* if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}

}

注意 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(bi); 需要导入头文件: import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder;
生成的结果如下: Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术

我们可以html.文件引用这个图片,identity.html 注意html中的路径问题;
<script>
function reloadImage() {
document.getElementById( 'btn').disabled = true;
document.getElementById( 'identity').src = 'http://localhost:8080/servlet/servlet/IdentityServlet?ts='
+ new Date().getTime();
}
</ script>

<img src="http://localhost:8080/servlet/servlet/IdentityServlet" id="identity" onload= "btn.disabled = false;" />
<input type= button value ="换个图片" onclick="reloadImage()" id="btn">

生成的结果如下: Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术

???Several ports (8005, 8080, 8009) required by Tomcat v6.0 Server at localhost are already in use. The server may already be running in another process, or a system process may be using the port. To start this server you will need to stop the other process or change the port number(s). 到任务管理器中把tomcat的运行关闭,就是java的进程
3.5 读取 web.xml参数 如果需求变化,修改源代码,重新编译class文件,然后重新部署。 常量信息更倾向于写在某个配置文件中。
3.5.1 初始化参数 web.xml配置初始化参数后,Servlet中提供方法getInitParameter(String param)获取初始化值 这些初始化参数也可以有ServletConfig对象取得。 eg notice.html放在/WEB-INF中,受保护的,通过程序读取 首先三个初始化参数
 <init-param >
<param-name >halloween</param-name>
<param-value >password </param-value>
</init-param >
<init-param >
<param-name >admin</param-name>
<param-value >admin</param-value>
</init-param >
<init-param >
<param-name >babyface</param-name>
<param-value >babyface</param-value>
</init-param >

然后InitParamServlet.java
public class InitParamServlet extends HttpServlet {

/**
* Constructor of the object.
*/
public InitParamServlet() {
super();
}

/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

request.setCharacterEncoding( "UTF-8");
response.setCharacterEncoding( "UTF-8");
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>请登录查看 Notice文件</TITLE></HEAD>" );
out.println( "<style> body, td, div {font-size:12px}</style>");
out.println( " <BODY>");
out.println( "<form action='" + request.getRequestURI() + "'method='post'>" );
out.println( "账号:<input type='text' name='username' style='width:200px;'> </br>" );
out.println( "密码:<input type='password' name='password' style='width:200px;'> <br/><br/>");
out.println( "<input type='submit' value=' 登录 '>");
out.println( "</form>");
out.println( " </BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}

/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

//提交的username/password参数
String username = request.getParameter("username" );
String password = request.getParameter("password" );

//所有的初始化参数名称
Enumeration params = this.getInitParameterNames();

//遍历所有的初始化参数
while(params .hasMoreElements()){
//参数名 即用户名 参数值 即密码
String usernameParam = (String)params.nextElement();
String passnameParam = getInitParameter(usernameParam );

//用户名 密码匹配
if(usernameParam .equalsIgnoreCase(username) && passnameParam.equals(password )){
request.getRequestDispatcher( "/WEB-INF/notice.html").forward(request ,response );
return ;
}
}
this.doGet(request , response );//不匹配 ,显示登录界面
}

/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
}

结果如下:登录后跳转到notice.html Java Web学习笔记 3 深入Servlet技术

Java Web学习笔记 3 深入Servlet技术 3.5.2  上下文参数 由于init-param在servlet中,所以不是全局参数,不能被其他servlet读取 配置所有的Servlet都能读取的,上下文参数使用标签<context-param>
 <context-param >
<param-name >upload folder </param-name>
<param-value >attachment </param-value>
</context-param >
<context-param >
<param-name >allowed file type </param-name>
<param-value >. gif,.jpg ,.bmp</param-value >
</context-param >
获取context-param可以使用ServletContext对象。 Servlet中通过getServletConfig(),getServletContext()获取 ContextParamServlet.java
public class ContextParamServlet extends HttpServlet {

/**
* @see HttpServlet#HttpServlet()
*/
public ContextParamServlet() {
super();
// TODO Auto-generated constructor stub
}

/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setCharacterEncoding("UTF-8");
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>读取上下文参数</TITLE></HEAD>");
out.println(" <link rel='stylesheet' type='text/css' href='../css/style.css'>");
out.println(" <BODY>");
out.println("<div align=center><br/>");
out.println("<fieldset style='width:90%'><legend>所有的上下文参数</legend><br/>");
//获取上下文
ServletContext servletContext = getServletConfig().getServletContext();
String uploadFoder = servletContext.getInitParameter("upload folder");
String allowedFileType = servletContext.getInitParameter("allowed file type");
out.println("<div class='line'>");
out.println(" <div align='left' class='leftDiv'>上传文件夹</div>");
out.println(" <div align='left' class='rightDiv'>" + uploadFoder + "</div>");
out.println("</div>");
out.println("<div class='line'>");
out.println(" <div align='left' class='leftDiv'>实际磁盘路径</div>");
out.println(" <div align='left' class='rightDiv'>" + servletContext.getRealPath(uploadFoder) + "</div>");
out.println("</div>");
out.println("<div class='line'>");
out.println(" <div align='left' class='leftDiv'>允许上传的类型</div>");
out.println(" <div align='left' class='rightDiv'>" + allowedFileType + "</div>");
out.println("</div>");
out.println("</fieldset></div>");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}

/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}

}
结果如下: Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术


3.5.3 资源注射
不需要Servlet主动去读取资源,Tomcat启动时候会把web.xml里配置的信息主动注射到Servlet中。 @Resource(name=“messageNameInWebXml”) private String message; 使用@Resource标注字符串message,表示message会在Servlet运行时动态注入, 然后再web.xml中配置一个名为messageNameInWebXml参数。 实例如下:InjectionServlet.java
public class InjectionServlet extends HttpServlet {


private @Resource(name="hello" ) String hello;//注入的字符串
private @Resource(name="i" ) int i;//注入的整数

@Resource(name= "persons")//两行的写法
private String persons;//注解与代码分开

/*
Context ctx = new InitialContext();
String message = (String)ctx.lookup("message");
Integer i =(Integer)ctx.lookup("i");
String persons = (String)ctx.lookup("persons");
*/

/**
* Constructor of the object.
*/
public InjectionServlet() {
super();
}

/**
* Destruction of the servlet. <br>
*/
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

response.setContentType( "text/html");
response.setCharacterEncoding( "UTF-8");
request.setCharacterEncoding( "UTF-8");

PrintWriter out = response.getWriter();
out.println( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println( "<HTML>");
out.println( " <HEAD><TITLE>资源注入</TITLE></HEAD>" );
out.println( "<style>body {font-size=12px; }</style>");

out.println( "<b>注入的字符串</b>: <br/>  - " + hello + "<br/>");
out.println( "<b>注入的整数</b>: <br/>  - " + i + "</br>");
out.println( "<b>注入的字符数组</b>:<br/>" );
for(String person :persons .split("," )){
out.println( "  - " + person +"<br/>");
}

out.println( " <BODY>");
out.println( " </BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}

/**
* Initialization of the servlet. <br>
*
* @throws ServletException if an error occurs
*/
public void init() throws ServletException {
// Put your code here
}
}

web.xml中使用标签<env-envy>来配置资源
<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 >InjectionServlet </servlet-name>
<servlet-class> servlet.InjectionServlet</servlet-class >
</servlet >
<servlet-mapping>
<servlet-name >InjectionServlet </servlet-name>
<url-pattern >/ servlet/InjectionServlet</url-pattern >
</servlet-mapping >
<!-- 下面是资源配置 -->
<env-entry >
<env-entry-name >hello </env-entry-name>
<env-entry-type >java.lang.String </env-entry-type>
<env-entry-value >Hello, Welcome to the JavaEE Resource Injection.</env-entry-value>
</env-entry >
<env-entry >
<env-entry-name >i </env-entry-name>
<env-entry-type >java.lang.Integer </env-entry-type>
<env-entry-value >30 </env-entry-value>
</env-entry >
<env-entry >
<env-entry-name >persons </env-entry-name>
<env-entry-type >java.lang.String </env-entry-type>
<env-entry-value >Helloween, Cobain, Rose, Axi,</env-entry-value >
</env-entry >
程序的运行效果如: Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
3.5.4 使用JNDI获取资源
Context ctx = new InitialContext();
String message = (String)ctx.lookup("message");
Integer i =(Integer)ctx.lookup("i");
String persons = (String)ctx.lookup("persons");

3.6 提交表单信息 客户端提交的信息可能来自表单里的文本框、密码框、文件域等,以参数形式提交到服务器。 Servlet的任务就是正确的获取这些信息,并根据信息做不同的响应。 提交的信息包括get/post,GET用于从服务器获取信息,Post用于向服务器提交信息。 POST提交信息包括:普通POST提交方式和可以上传文件的POST提交方式。
3.6.1GET实现搜素引擎 HTML使用FORM提交数据,action属性设置将数据提交到哪个URL。 GET方式提交,变量之间&连接,Servlet路径+问号?+查询字符串的形式获取服务器内容。 GET提交的典型方式就是搜索引擎。
新建search.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title> search.html</title >
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style> div, body, span {font-size:14px; } </style>
</head>

<body>
<div align= "center">
<img src="image/yahoo.gif" style=' margin: 25px; '>
<div >
<form action= '/servlet/servlet/SearchServlet' method='get' >
<input type= "radio" name ="type" value="web" checked>网页
<input type= "radio" name ="type" value="news" >新闻
<input type= "radio" name ="type" value="image" >图片
<input type= "radio" name ="type" value="video" >视频       
<input type= "checkbox" name ="allowedAdult" value="true" >允许成人内容 <br/>< br/>
<input type= "text" name ="word" value="" style="width :300px; "> <input type="submit" value= "用雅虎搜索" style=" width: 100px; ">
</form>
</div >
<div style=" margin-top:50px ; ">
&copy; Helloween 2007-2010
</div >
</div>

</body>
</html>

然后写一个searchServlet实现关键的业务逻辑部分:搜索引擎程序。 这里使用Yahoo API,所以要加yahoo_search-2.0.1.jar加入到库中,即/WEB-INF/lib SearchServlet.java
public class SearchServlet extends HttpServlet {

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

response.setCharacterEncoding( "UTF-8");
request.setCharacterEncoding( "UTF-8");

// 搜索关键字
String word = request.getParameter( "word");
// 搜索类型
String type = request.getParameter( "type");
// 是否允许成人内容。如果选中,则为 "true",否则为 null.
String allowedAdult = request.getParameter("allowedAdult" );

boolean adultOk = "true" .equals(allowedAdult );

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>" + word + " 搜索结果</TITLE></HEAD>" );
out.println( "<style>");
out.println( " body, div {font-size:12px; padding:2px; margin:0px; }");
out.println( " .imgDiv{float:left; width: 172px; height:250px; margin:2px; padding:2px; border:1px pink solid; overflow:hidden; }");
out.println( "</style>");
out.println( " <BODY>");

out.println( "<div style='float:left; height:40px; '><img src='../images/yahoo.gif'></div>");
out.println( "<form action='" + request.getRequestURI() + "' method='get'>" );
out.println( " <div style='height:40px; '>" );
out.println( " <input type='radio' name='type' value='web' " + (type.equals("web" )?"checked" :"" ) + ">网页" );
out.println( " <input type='radio' name='type' value='news' " + (type.equals("news" )?"checked" :"" ) + ">新闻" );
out.println( " <input type='radio' name='type' value='image' " + (type.equals("image" )?"checked" :"" ) + ">图像" );
out.println( " <input type='radio' name='type' value='video' " + (type.equals("video" )?"checked" :"" ) + ">视频" );
out.println( "       " );
out.println( " <input type='checkbox' name='allowedAdult' value='true' " + (adultOk?"checked" :"" ) + ">允许成人内容 <br/>" );
out.println( " <input type='text' name='word' value='" + word + "' style='width:300px; '> <input type='submit' value='用雅虎搜索' style='width:100px; '>");
out.println( " </div>");
out.println( "</form>");

SearchClient client = new SearchClient("javasdktest" );

try{
if("image" .equals(type )){
ImageSearchRequest searchRequest = new ImageSearchRequest(URLEncoder.encode( word, "UTF-8"));
// 是否显示成人内容
searchRequest.setAdultOk(adultOk );
// 查询记录数
searchRequest.setResults(20);
// 从第 0 条记录开始显示
searchRequest .setStart(BigInteger.valueOf (0));

double startTime = System.currentTimeMillis();
ImageSearchResults results = client.imageSearch(searchRequest );
double endTime = System.currentTimeMillis();

out.println( "<div align=right style='width:100%; background: #FFDDDD; height:25px; padding:2px; border-top:1px solid #FF9999; margin-bottom:5px; '>");
out.println( " 总共 " + results.getTotalResultsAvailable() + " 条数据,总用时 " + ( endTime - startTime )/1000 + " 秒。");
out.println( "</div>");

for(ImageSearchResult result : results.listResults()){
out.println( "<div class='imgDiv'>");
out.println( " <div align='center'><a href=\"" + result.getClickUrl() + "\" target=_blank><img width=160 height=120 src=\"" + result.getThumbnail().getUrl() + "\" border='0'></a></div>");
out.println( " <div align='center'><a href=\"" + result.getRefererUrl() + "\" target=_blank>" + result.getTitle() + "</a></div>" );
out.println( " <div align='center'>" + result.getWidth() + "x" + result .getHeight() + " " + result.getFileFormat() + "</div>" );
out.println( " <div>" + (result.getSummary()==null ? "" : result.getSummary()) + "</div>");
out.println( "</div>");
}
}
else if ("web" .equals(type )){
WebSearchRequest searchRequest = new WebSearchRequest(URLEncoder.encode(word, "UTF-8"));
// 是否显示成人内容
searchRequest.setAdultOk(adultOk );
// 查询记录数
searchRequest.setResults(20);
// 从第 0 条记录开始显示
searchRequest .setStart(BigInteger.valueOf (0));

double startTime = System.currentTimeMillis();
WebSearchResults results = client.webSearch(searchRequest );
double endTime = System.currentTimeMillis();

out.println( "<div align=right style='width:100%; background: #FFDDDD; height:25px; padding:2px; border-top:1px solid #FF9999; margin-bottom:5px; '>");
out.println( " 总共 " + results.getTotalResultsAvailable() + " 条数据,总用时 " + ( endTime - startTime )/1000 + " 秒。");
out.println( "</div>");
for(WebSearchResult result : results.listResults()){
out.println( "<div style='margin:8px; width:500px; '>");
out.println( " <div><a href=\"" + result.getClickUrl() + "\" target=_blank><b>" + result.getTitle() + "</b></a> 文件格式:" + result.getMimeType() + "</div>" );
out.println( " <div>网址:<a href=\"" + result.getUrl() + "\" target=_blank>" + result .getUrl() + "</a></div>" );
out.println( " <div>" + result.getSummary() + (result .getCache()==null ? "" : " [<a href=\"" + result.getCache().getUrl() + "\" target=_blank>网页快照</a>]") + "</div>");

out.println( "</div>");
}
}
else if ("news" .equals(type )){

NewsSearchRequest searchRequest = new NewsSearchRequest(URLEncoder.encode( word, "UTF-8"));
// 是否显示成人内容
// searchRequest.setAdultOk(adultOk);
// 查询记录数
searchRequest.setResults(20);
// 从第 0 条记录开始显示
searchRequest .setStart(BigInteger.valueOf (0));

double startTime = System.currentTimeMillis();
NewsSearchResults results = client.newsSearch(searchRequest );
double endTime = System.currentTimeMillis();

out.println( "<div align=right style='width:100%; background: #FFDDDD; height:25px; padding:2px; border-top:1px solid #FF9999; margin-bottom:5px; '>");
out.println( " 总共 " + results.getTotalResultsAvailable() + " 条数据,总用时 " + ( endTime - startTime )/1000 + " 秒。");
out.println( "</div>");
for(NewsSearchResult result : results.listResults()){
out.println( "<div style='margin:8px; width:500px; '>");
out.println( " <div><a href=\"" + result.getClickUrl() + "\" target=_blank><b>" + result.getTitle() + "</b></a></div>" );
out.println( " <div>网址:<a href=\"" + result.getUrl() + "\" target=_blank>" + result .getUrl() + "</a></div>" );
out.println( " <div>" + result.getSummary() + "</div>" );
out.println( "</div>");
}
}
else if ("video" .equals(type )){
VideoSearchRequest searchRequest = new VideoSearchRequest(URLEncoder.encode( word, "UTF-8"));
// 是否显示成人内容
searchRequest.setAdultOk(adultOk );
// 查询记录数
searchRequest.setResults(20);
// 从第 0 条记录开始显示
searchRequest .setStart(BigInteger.valueOf (0));

double startTime = System.currentTimeMillis();
VideoSearchResults results = client.videoSearch(searchRequest );
double endTime = System.currentTimeMillis();

out.println( "<div align=right style='width:100%; background: #FFDDDD; height:25px; padding:2px; border-top:1px solid #FF9999; margin-bottom:5px; '>");
out.println( " 总共 " + results.getTotalResultsAvailable() + " 条数据,总用时 " + ( endTime - startTime )/1000 + " 秒。");
out.println( "</div>");

for(VideoSearchResult result : results.listResults()){
out.println( "<div class='imgDiv'>");
out.println( " <div align='center'><a href=\"" + result.getClickUrl() + "\" target=_blank><img width=160 height=120 src=\"" + result.getThumbnail().getUrl() + "\" border='0'></a></div>");
out.println( " <div align='center'><a href=\"" + result.getRefererUrl() + "\" target=_blank>" + result.getTitle() + "</a></div>" );
out.println( " <div align='center'>" + result.getWidth() + "x" + result.getHeight() + " " + result .getFileFormat() + "</div>");
out.println( " <div>" + (result.getSummary()==null ? "" : result.getSummary()) + "</div>");
out.println( "</div>");
}
}
} catch(Exception e ){
e.printStackTrace();
out.println( "<font color=red>Exception: " + e.getMessage() + "</font>" );
}

out.println( " </BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}
}
运行,直接访问http://localhost:8080/servlet/servlet/SearchServlet是不行的:

HTTP Status 500 -


type Exception report

message

description The server encountered an internal error that prevented it from fulfilling this request.

exception

java.lang.NullPointerException
servlet.searchServlet.doGet(searchServlet.java:64)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:723)

note The full stack trace of the root cause is available in the Apache Tomcat/6.0.44 logs.

直接访问肯定是不对的。
首先键入正确的search.html的地址如下:进行搜索 Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 跳转到SearchServlet的页面 Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 出现如上结果,有可能yahoo的API问题,不管了,只需要留意地址栏的搜索内容。
如果想在该搜索引擎搜中文,需要修改Tomcat目录下的\conf\server.xml里设定的默认的GET编码方式, <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8"/>
GET提交表单时,提交的内容显示在地址栏中,并会被记录在缓存中,因此提交敏感的信息不能使用GET, 并且GET提交URL总长度不能超过255个字符,因此提交过长的内容时也不能使用GET。
3.6.2 POST提交个人信息 把HTML中的FORM的method设置为POST。 新建postPersonalInformation.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title> 提交用户信息</title >
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<style>
body, div, td, input { font-size:12px ; margin :0px; }
select {height :20px; width:300px; }
.title {font-size : 16px; padding: 10px; margin: 10px; width:80% ; }
.text {height :20px; width:300px; border: 1px solid #AAAAAA; }
.line {margin :2px; }
.leftDiv {width :110px; float:left; height: 22px; line-height:22px ; font-weight :bold; }
.rightDiv {height :22px; }
.button {
color:#fff;
font-weight: bold;
font-size: 11px;
text-align:center;
padding:.17em 0 .2em .17em;
border-style: solid;
border-width: 1px;
border-color: #9cf #159 #159 #9cf;
background:#69c url(images/bg-btn-blue.gif) repeat-x;
}
</style>
</head>
<body>
<form action= "/servlet/servlet/PostServlet" method="POST" >
<div align= "center">
<br />
<fieldset style='width:90%'>
<legend> 填写用户信息</legend >
<br/>
<div class= 'line'>
<div align= "left" class ='leftDiv'>请填写您的姓名:</div >
<div align= "left" class ='rightDiv'>
<input type= "text" name ="name" class="text" />
</div>
</div>
<div class= 'line'>
<div align= "left" class ='leftDiv'>请填写您的密码:</div >
<div align= "left" class ='rightDiv'>
<input type= "password" name ="password" class="text" />
</div>
</div>
<div class= 'line'>
<div align= "left" class ='leftDiv'>请再次输入密码:</div >
<div align= "left" class ='rightDiv'>
<input type= "password" name="passwordConfirm" class="text" />
</div>
</div>
<div class= 'line'>
<div align= "left" class ='leftDiv'>请选择性别:</div >
<div align= "left" class ='rightDiv'>
<input type= "radio" name ="sex" value="男" id="sexMale">
<label for= "sexMale">男 </label>
<input type= "radio" name ="sex" value="女" id="sexFemale">
<label for= "sexFemale">女 </label>
</div>
</div>
<div class= 'line'>
<div align= "left" class ='leftDiv'>请输入年龄:</div >
<div align= "left" class ='rightDiv'>
<input type= "text" name ="age" class="text" >
</div>
</div>
<div class= 'line'>
<div align= "left" class ='leftDiv'>请输入生日:</div >
<div align= "left" class ='rightDiv'>
<input type= "text" name ="birthday" class="text" >
<br/> 格式:"yyyy -mm-dd"
</div>
</div>
<div class= 'line'>
<div align= "left" class ='leftDiv'>请选择您的爱好</div >
<div align= "left" class ='rightDiv'>
<input type= "checkbox" name="interesting" value="音乐影视" id ="i1">
<label for= "i1">音乐影视 </label>
<input type= "checkbox" name="interesting" value="外出旅游" id ="i2">
<label for= "i2">外出旅游 </label>
<input type= "checkbox" name="interesting" value="社交活动" id ="i3">
<label for= "i3">社交活动 </label>
</div>
</div>
<div class= 'line'>
<div align= "left" class ='leftDiv'>请选择省市:</div >
<div align= "left" class ='rightDiv'>
<select name= "area">
<option> ---请选择省份---</option >
<optgroup label= "北京市" >
<option value= "北京市海淀区" >海淀区 </option>
<option value= "北京市朝阳区" >朝阳区 </option>
<option value= "北京市东城区" >东城区 </option>
<option value= "北京市西城区" >西城区 </option>
</optgroup>
<optgroup label= "山东省" >
<option value= "山东省济南市" >济南市 </option>
<option value= "山东省青岛市" >青岛市 </option>
<option value= "山东省潍坊市" >潍坊市 </option>
</optgroup>
</select>
</div>
</div>
<div class= 'line'>
<div align= "left" class ='leftDiv'>自我描述:</div >
<div align= "left" class ='rightDiv'>
<textarea name= "description" rows ="8" style="width :300px; ">请填写其他资料... </textarea>
</div>
</div>
<div class= 'line'>
<div align= "left" class ='leftDiv'></div>
<div align= "left" class ='rightDiv'>
<br/>< input type ="submit" name= "btn" value=" 提交信息 " class="button">< br/>
</div>
</div>
</fieldset >
</div>
</form>
</body>
</html>
如下所示: Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术

再编写一个Servlet接收HTML页面提交的信息, PostServlet.java
public class PostServlet extends HttpServlet {

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

response.setCharacterEncoding( "UTF-8");
response.getWriter().println( "请使用 POST 方式提交数据。" );
}

/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

response.setCharacterEncoding( "UTF-8");
request.setCharacterEncoding( "UTF-8");

// 从 文本框 text 中取姓名
String name = request.getParameter( "name");
// 从 密码域 password 中取密码
String password = request.getParameter("password" );
// 从 单选框 checkbox 中取性别
String sex = request.getParameter( "sex");

int age = 0;
try {
// 取 年龄. 需要把 字符串 转换为 int.
// 如果格式不对会抛出 NumberFormattingException
age = Integer.parseInt(request.getParameter( "age"));
} catch (Exception e ) {
}

Date birthday = null;
try {
// 取 生日. 需要把 字符串 转化为 Date.
// 如果格式不对会抛出 ParseException
DateFormat format = new SimpleDateFormat("yyyy-MM-dd" );
birthday = format.parse(request .getParameter("birthday"));
} catch (Exception e ) {
}

// 从 多选框 checkbox 中取多个值
String[] interesting = request.getParameterValues("interesting" );
// 从 下拉框 select 中取值
String area = request .getParameter("area");
// 从 文本域 textarea 中取值
String description = request.getParameter("description" );

// 取 提交按钮 的键值
String btn = request.getParameter( "btn");

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>感谢您提交信息</TITLE>" );
out.println( "<style>");
out.println( "body, div, td, input {font-size:12px; margin:0px; }");
out.println( ".line {margin:2px; }");
out
.println( ".leftDiv {width:110px; float:left; height:22px; line-height:22px; font-weight:bold; }");
out.println( ".rightDiv {height:22px; line-height:22px; }");
out.println( ".button {");
out.println( " color:#fff;");
out.println( " font-weight:bold;");
out.println( " font-size: 11px; ");
out.println( " text-align:center;");
out.println( " padding:.17em 0 .2em .17em;" );
out.println( " border-style:solid;");
out.println( " border-width:1px;");
out.println( " border-color:#9cf #159 #159 #9cf;");
out
.println( " background:#69c url(/servlet/images/bg-btn-blue.gif) repeat-x;");
out.println( "</style>");
out.println( "</HEAD>");

out.println( "<div align=\"center\"><br/>" );
out.println( "<fieldset style='width:90%'><legend>填写用户信息</legend><br/>");

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>您的姓名:</div>");
out.println( " <div align='left' class='rightDiv'>" + name + "</div>");
out.println( " </div>" );

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>您的密码:</div>");
out.println( " <div align='left' class='rightDiv'>" + password
+ "</div>");
out.println( " </div>" );

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>您的性别:</div>");
out.println( " <div align='left' class='rightDiv'>" + sex + "</div>");
out.println( " </div>" );

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>您的年龄:</div>");
out.println( " <div align='left' class='rightDiv'>" + age + "</div>");
out.println( " </div>" );

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>您的生日:</div>");
out.println( " <div align='left' class='rightDiv'>");
out.println( new SimpleDateFormat("yyyy年MM月dd日" ).format(birthday));
out.println( " </div>" );
out.println( " </div>" );

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>您的兴趣:</div>");
out.println( " <div align='left' class='rightDiv'>");

if (interesting != null)
for (String str : interesting ) {
out.println( str + ", ");
}

out.println( " </div>" );
out.println( " </div>" );

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>自我描述:</div>");
out.println( " <div align='left' class='rightDiv'>" + description
+ "</div>");
out.println( " </div>" );

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>按钮键值:</div>");
out.println( " <div align='left' class='rightDiv'>" + btn + "</div>");
out.println( " </div>" );

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'></div>");
out.println( " <div align='left' class='rightDiv'>");
out
.println( " <br/><input type='button' name='btn' value='返回上一页' onclick='history.go(-1); ' class='button'><br/>" );
out.println( " </div>" );
out.println( " </div>" );

out.println( "<BODY>");
out.println( "</BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}
}
提交如下页面,出现错误: Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术Java Web学习笔记 3 深入Servlet技术 查看出错原因,主要是:没注意生日的格式
重新填写如下: Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 接受到信息如下: Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 3.6.3 上传文件客户端 上传文件需要设置FORM的enctype属性为multipart/form-data,由于上传文件比较大, 需要设置该参数指定浏览器使用二进制上传, 如果不设置,entype默认为:application/x-www-form-urlencoded,使用ASCII发送,导致发送失败 上传文件需要使用文件域(<input type="file"/>),并把FORM的Enctype设置为multipart/form-data。 upload.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title> 上传文件</title >
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3" >
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel= "stylesheet" type ="text/css" href="css/style.css" >
</head>
<body>
<form action= "servlet/UploadServlet" method="post" enctype="multipart/form-data" >
<div align= "center"><br />
<fieldset style=" width: 90%">
<legend> 上传文件</legend ><br/>
<div class= 'line'>
<div align= 'left' class ="leftDiv"> 上传文件一</div >
<div align= 'left' class ="rightDiv">
<input type= "file" name ="file1" class="text" >
</div>
</div>
<div class= 'line'>
<div align= 'left' class ="leftDiv"> 上传文件二</div >
<div align= 'left' class ="rightDiv">
<input type= "file" name ="file2" class="text" >
</div>
</div>
<div class= 'line'>
<div align= 'left' class ="leftDiv"> 上传文件说明一 </div>
<div align= 'left' class ="rightDiv">< input type="text" name="description1" class= "text"></div >
</div>
<div class= 'line'>
<div align= 'left' class ="leftDiv"> 上传文件说明二 </div>
<div align= 'left' class ="rightDiv">< input type="text" name="description2" class= "text"></div >
</div>
<div class= 'line'>
<div align= 'left' class ="leftDiv"></ div>
<div align= 'left' class ="rightDiv">< br/>
<input type= "submit" value =" 上传文件 " class="button">
</div>
</div>
</fieldset >
</div>
</form>
</body>
</html>
结果如下: Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
服务端比较复杂,解析而进程数据流比较麻烦。 SmartUpload类库,解析request过程中 放于内存中,速度快,但较大文件会发生溢出。 Commons FileUpload框架:
首先将类库的jar文件加入项目中 Java Web学习笔记 3 深入Servlet技术 新建UploadServlet.java
public class UploadServlet extends HttpServlet {

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

response.setContentType( "text/html");
response.getWriter().println( "请以POST方式上传文件" );
}

/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
@SuppressWarnings( "unchecked") //消除unchecked warning
public void doPost(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

File file1 = null, file2 = null;
String description1 = null , description2 = null;

response.setCharacterEncoding( "UTF-8");
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( " <link rel='stylesheet' type='text/css' href='../css/style.css'>");
out.println( " <BODY>");

out.println( "<div align=center><br/>" );
out.println( "<fieldset style='width:90%'><legend>上传文件</legend><br/>");

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>上传日志:</div>");
out.println( " <div align='left' class='rightDiv'>");

// 使用 DiskFileUpload 对象解析 request
DiskFileUpload diskFileUpload = new DiskFileUpload();
try {
// 将 解析的结果 放置在 List 中
List<FileItem> list = diskFileUpload.parseRequest(request);
out.println( "遍历所有的 FileItem ... <br/>");
// 遍历 list 中所有的 FileItem
for(FileItem fileItem : list ){

if(fileItem .isFormField()){
// 如果是 文本域
if("description1" .equals(fileItem .getFieldName())){
// 如果该 FileItem 名称为 description1
out.println( "遍历到 description1 ... <br/>");
description1 = new String(fileItem.getString().getBytes(), "UTF-8" );
}
if("description2" .equals(fileItem .getFieldName())){
// 如果该 FileItem 名称为 description2
out.println( "遍历到 description2 ... <br/>");
description2 = new String(fileItem.getString().getBytes(), "UTF-8" );
}
}
else{
// 否则,为文件域
if("file1" .equals(fileItem .getFieldName())){
// 客户端文件路径构建的 File 对象
File remoteFile = new File(new String(fileItem .getName().getBytes(), "UTF-8"));
out.println( "遍历到 file1 ... <br/>");
out.println( "客户端文件位置: " + remoteFile.getAbsolutePath() + "<br/>");
// 服务器端文件,放在 upload 文件夹下
file1 = new File(this.getServletContext().getRealPath("attachment" ), remoteFile.getName());
file1.getParentFile().mkdirs();
file1.createNewFile();

// 写文件,将 FileItem 的文件内容写到文件中
InputStream ins = fileItem.getInputStream();
OutputStream ous = new FileOutputStream(file1);

try{
byte[] buffer = new byte[1024];
int len = 0;
while((len =ins .read(buffer )) > -1)
ous.write( buffer, 0, len);
out.println( "已保存文件" + file1.getAbsolutePath() + "<br/>" );
} finally{
ous.close();
ins.close();
}
}
if("file2" .equals(fileItem .getFieldName())){
// 客户端文件路径构建的 File 对象
File remoteFile = new File(new String(fileItem .getName().getBytes(), "UTF-8"));
out.println( "遍历到 file2 ... <br/>");
out.println( "客户端文件位置: " + remoteFile.getAbsolutePath() + "<br/>");
// 服务器端文件,放在 upload 文件夹下
file2 = new File(this.getServletContext().getRealPath("attachment" ), remoteFile.getName());
file2.getParentFile().mkdirs();
file2.createNewFile();

// 写文件,将 FileItem 的文件内容写到文件中
InputStream ins = fileItem.getInputStream();
OutputStream ous = new FileOutputStream(file2);

try{
byte[] buffer = new byte[1024];
int len = 0;
while((len =ins .read(buffer )) > -1)
ous.write( buffer, 0, len);
out.println( "已保存文件" + file2.getAbsolutePath() + "<br/>" );
} finally{
ous.close();
ins.close();
}
}
}
}
out.println( "Request 解析完毕" );
} catch (FileUploadException e ) {
// TODO Auto-generated catch block
e.printStackTrace();
}

out.println( " </div>" );
out.println( " </div>" );

if(file1 != null){
out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>file1:</div>");
out.println( " <div align='left' class='rightDiv'>");
out.println( " <a href='" + request.getContextPath() + "/attachment/" + file1.getName() + "' target=_blank>" + file1 .getName() + "</a>" );
out.println( " </div>" );
out.println( " </div>" );
}

if(file2 != null){
out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>file2:</div>");
out.println( " <div align='left' class='rightDiv'>");
out.println( " <a href='" + request.getContextPath() + "/attachment/" + URLEncoder.encode(file2.getName(), "UTF-8") + "' target=_blank>" + file2.getName() + "</a>");
out.println( " </div>" );
out.println( " </div>" );
}


out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>description1:</div>");
out.println( " <div align='left' class='rightDiv'>");
out.println( description1);
out.println( " </div>" );
out.println( " </div>" );

out.println( " <div class='line'>" );
out.println( " <div align='left' class='leftDiv'>description2:</div>");
out.println( " <div align='left' class='rightDiv'>");
out.println( description2);
out.println( " </div>" );
out.println( " </div>" );

out.println( "</fieldset></div>" );

out.println( " </BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}

}
点击上传文件,发生错误 Java Web学习笔记 3 深入Servlet技术



HTTP Status 500 - The filename, directory name, or volume label syntax is incorrect
查了下:在英文操作系统下安装软件时,不要把安装包放在中文命名的文件夹下,也不要安装在以中文命名的文件夹下。 最好把安装包放在磁盘的根目录下,安装完成后再移动到其它目录中备份,不论是英文还是中文系统,安装数据库都不允许安装在以中文命名的文件夹下。 总结下来:不是路径的问题,就是文件的命名问题,更有可能是命名。 换个路径文件上传,OK。 Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 上传文件以二进制形式提交,而非ASCII方式提交,因为Servlet不能用request.getParameter()等方式获取提交的文本内容。
3.7 带进度条的文件上传 UploadServlet只实现了普通的文件上传,如果需要显示上传进度,速度等,还需配合Ajax技术。
实时显示上传进度的原理是服务器在处理上传文件同时,将上传君度的信息写入session中, 客户端利用Ajax技术开一个线程从session中获取上传进度的信息,并实时显示。
3.7.2 上传进度条 上传进度条两个<div>标签实现,css属性显示一个HTML版的难度条 upload.jsp
<style type= "text/css">
#progressBar {
width: 400px;
height: 12px;
background: #FFFFFF;
border: 1px solid #000000;
padding: 1 px
}
#progressBarItem {
width: 20%;
height: 100%;
background: #FF0000;
}
</style>
<div id= "progressBar"><div id="progressBarItem" ></div></ div>

结果如下: Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
3.7.3 上传监听器 UploadListener.java
public class UploadListener implements ProgressListener {

//记录上传信息的Java Bean
private UploadStatus status;

public UploadListener(UploadStatus status) {
// TODO Auto-generated constructor stub
this.status = status ;
}

//已读取的数据长度,文件的总长度,正在保存第几个文件
public void update(long bytesRead , long contentLength, int items ) {
// TODO Auto-generated method stub
status.setBytesRead( bytesRead);
status.setContentLength( contentLength);
status.setItems( items);
}
添加了该监听器后,上传组件在上传文件时,不断的回调该方法,回传这些数据。 利用这些数据可以实时显示,因此需要保存数据,保存到UploadStatus中,普通的Java Bean UploadStatus.java
public class UploadStatus {

//已读取的数据长度,文件的总长度,正在保存第几个文件,开始上传的时间,用于计算上传速率
private long bytesRead;
private long contentLength;
private int items;
private long startTime = System.currentTimeMillis();

//构造方法 set/get
public long getBytesRead() {
return bytesRead;
}

public void setBytesRead(long bytesRead) {
this.bytesRead = bytesRead;
}

public long getContentLength() {
return contentLength;
}

public void setContentLength(long contentLength) {
this.contentLength = contentLength;
}

public int getItems() {
return items;
}

public void setItems(int items) {
this.items = items;
}

public long getStartTime() {
return startTime;
}

public void setStartTime(long startTime) {
this.startTime = startTime;
}
}

3.7.4 监听上传进度 监听上传过程需要为ServletFileUpload安装一个监听器,然后把存有上传进度信息的UploadStatus对象 放入Session,上传文件使用的Post方法; ProgressUploadServlet.java
public class ProgressUploadServlet extends HttpServlet {

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

response.setHeader( "Cache-Control", "no-store" );
response.setHeader( "Pragrma", "no-cache" );
response.setDateHeader( "Expires", 0);

UploadStatus status = (UploadStatus) request.getSession(true)
.getAttribute( "uploadStatus");

if (status == null) {
response.getWriter().println( "没有上传信息" );
return;
}

long startTime = status .getStartTime();
long currentTime = System.currentTimeMillis ();

// 已传输的时间 单位:s
long time = (currentTime - startTime ) / 1000 + 1;

// 传输速度 单位:byte/s
double velocity = ((double) status.getBytesRead()) / (double) time;

// 估计总时间 单位:s
double totalTime = status .getContentLength() / velocity;

// 估计剩余时间 单位:s
double timeLeft = totalTime - time ;

// 已完成的百分比
int percent = (int) (100 * (double) status.getBytesRead() / (double) status
.getContentLength());

// 已完成数 单位:M
double length = ((double) status.getBytesRead()) / 1024 / 1024;

// 总长度 单位:M
double totalLength = ((double) status.getContentLength()) / 1024 / 1024;

// 格式:百分比||已完成数(M)||文件总长度(M)||传输速率(K)||已用时间(s)||估计总时间(s)||估计剩余时间(s)||正在上传第几个文件
String value = percent + "||" + length + "||" + totalLength + "||"
+ velocity + "||" + time + "||" + totalTime + "||" + timeLeft
+ "||" + status .getItems();

response.getWriter().println( value);
}

/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to
* post.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doPost(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

// 上传状态
UploadStatus status = new UploadStatus();

// 监听器
UploadListener listener = new UploadListener(status);

// 把 UploadStatus 放到 session 里
request.getSession( true).setAttribute("uploadStatus" , status);

// Apache 上传工具
ServletFileUpload upload = new ServletFileUpload(
new DiskFileItemFactory());

// 设置 listener
upload.setProgressListener( listener);

try {
List itemList = upload.parseRequest(request );

for (Iterator it = itemList.iterator(); it.hasNext();) {
FileItem item = (FileItem) it.next();
if (item .isFormField()) {
System. out.println("FormField: " + item.getFieldName()
+ " = " + item.getString());
} else {
System. out.println("File: " + item.getName());

// 统一 Linux 与 windows 的路径分隔符
String fileName = item.getName().replace("/" , "\\" );
fileName = fileName.substring(fileName .lastIndexOf("\\"));

File saved = new File("C:\\upload_test" , fileName );
saved.getParentFile().mkdirs();

InputStream ins = item.getInputStream();
OutputStream ous = new FileOutputStream(saved);

byte[] tmp = new byte[1024];
int len = -1;

while ((len = ins .read(tmp )) != -1) {
ous.write( tmp, 0, len);
}

ous.close();
ins.close();

response.getWriter().println( "已保存文件:" + saved );
}
}
} catch (Exception e ) {
e.printStackTrace();
response.getWriter().println( "上传发生错误:" + e .getMessage());
}
}
}

3.7.5 读取上传进度 上传进度保存在session中的uploadStatus属性中,上传文件只使用了dopost方法,没有占用doGet方法, 所以使用doget方法读取上传进度。
3.7.6 显示上传进度 上传文件时,如果不对但处理,提交表单进入另一个页面,造成页面刷新。 要使表单内容不变,同时显示进度条,直到文件上传结束,从而避免白屏,方法更改FORM的target属性
target属性默认_self,如果默认,提交后的新页面会在当前窗口显示,造成当前偶短暂白屏。 在该页面添加隐藏的iframe,将target属性指定为该iframe,则提交的新页面在iframe中显示。
表单提交了onsubmit=“showStatus()”事件,表单提交会执行页面的showStatus方法。
Ajax能够不断刷新页面改变页面的内容,原理是创建一个request,用这个request获取其他页面的内容,并显示在页面上,因为没有在浏览器键入地址,所以不会有刷新、抖动等。 Ajax核心就是request,学名XMLHttpRequest。 progressUpload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title> Insert title here</title >
<style type= "text/css">
body, td, div {font-size: 12px; font-familly: 宋体 ; }
#progressBar {width : 400px; height: 12px; background: #FFFFFF; border : 1px solid #000000; padding: 1px; }
#progressBarItem {width : 30%; height: 100%; background: #FF0000; }
</style>
</head>

<body>

<iframe name= upload_iframe width =0 height=0></ iframe>

<form action= "servlet/ProgressUploadServlet" method="post" enctype="multipart/form-data" target="upload_iframe" onsubmit="showStatus(); ">

<input type= "file" name ="file1" style=" width: 350px; "> <br />
<input type= "file" name ="file2" style=" width: 350px; "> <br />
<input type= "file" name ="file3" style=" width: 350px; "> <br />
<input type= "file" name ="file4" style=" width: 350px; "> <input type= "submit"
value= " 开始上传 " id="btnSubmit"></ form>

<div id= "status" style ="display : none; ">
上传进度条:
<div id="progressBar">< div id="progressBarItem" ></div></ div>
<div id="statusInfo"></ div>
</div>

<br/>
<br/>
<br/>
<br/>
<br/>

<script type= "text/javascript">

var _finished = true;

function $(obj){
return document.getElementById(obj);
}

function showStatus(){
_finished = false;
$( 'status').style.display = 'block' ;
$( 'progressBarItem').style.width = '1%' ;
$( 'btnSubmit').disabled = true;

setTimeout( "requestStatus()" , 1000);
}

function requestStatus(){

if(_finished) return;

var req = createRequest();

req.open( "GET", "servlet/ProgressUploadServlet" );
req.onreadystatechange= function(){callback(req);}
req.send( null);

setTimeout( "requestStatus()" , 1000);
}

function createRequest()
{
if(window.XMLHttpRequest)//ns
{
return new XMLHttpRequest();
} else//IE
{
try{
return new ActiveXObject("Msxml2.XMLHTTP" );
} catch(e){
return new ActiveXObject("Microsoft.XMLHTTP");
}
}
return null;
}
function callback(req){

if(req.readyState == 4) {
if(req.status != 200){
_debug( "发生错误。 req.status: " + req.status + "" );
return;
}

_debug( "status.jsp 返回值:" + req.responseText);

var ss = req.responseText.split("||");

// 格式:百分比||已完成数(M)||文件总长度(M)||传输速率(K)||已用时间(s)||估计总时间(s)||估计剩余时间(s)||正在上传第几个文件
$( 'progressBarItem').style.width = '' + ss[0] + '%';
$( 'statusInfo').innerHTML = '已完成百分比: ' + ss[0] + '% <br />已完成数(M): ' + ss[1] + '<br/>文件总长度(M): ' + ss[2] + '<br/>传输速率(K): ' + ss[3] + '<br/>已用时间(s): ' + ss[4] + '<br/>估计总时间(s): ' + ss[5] + '<br/>估计剩余时间(s): ' + ss[6] + '<br/>正在上传第几个文件: ' + ss[7];

if(ss[1] == ss[2]){
_finished = true;
$( 'statusInfo').innerHTML += "<br/><br/><br/>上传已完成。" ;
$( 'btnSubmit').disabled = false;
}
}
}
function _debug(obj){
var div = document.createElement("DIV");
div.innerHTML = "[debug]: " + obj;
document.body.appendChild(div);
}
</ script>
</body>
</html>
Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 3.8 Servlet生命周期 Servlet的声明周期由web服务器来维护。
在CGI编程中,每请求一次CGI程序,服务器单独的进程处理请求,完毕后再销毁。 Servlet:服务器启动时(load-on-startup=1)或者 第一次请求Servlet(load-on-startup=0)初始化一个Servlet对象,然后利用这个对象去处理所有的客户端请求,服务器关闭才销毁这个Servlet独享。 Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术
eg 前面例子都是从doget或doPost中读取初始化参数,每次执行读取一次,效率低下, 将其放在init中,即保证了只读取一次,又保证不耽误doGet,doPost使用。 LifeCycleServlet.java
public class LifeCycleServlet extends HttpServlet {

// 个税起征点 从配置文件中读取
private static double startPoint = 0;

/**
* Initialization of the servlet. <br>
*
* @throws ServletException
* if an error occurs
*/
public void init() throws ServletException {
// Put your code here
this.log("执行init()方法...." );
ServletConfig conf = this.getServletConfig();
startPoint = Double.parseDouble(conf.getInitParameter( "startPoint"));
}

@Override
protected void service(HttpServletRequest arg0 , HttpServletResponse arg1)
throws ServletException, IOException {
// TODO Auto-generated method stub
this.log("执行service()方法..." );
super.service(arg0 , arg1 );// 首先会执行service()方法
}

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

this.log("执行 doGet() 方法 ... " );
response.setCharacterEncoding( "UTF-8");
response.setContentType( "text/html");
PrintWriter out = response.getWriter();
out.println( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println( "<link rel='stylesheet' type='text/css' href='../css/style.css'>");
out.println( "<HTML><HEAD><TITLE>个人所得税计算</TITLE></HEAD>" );

out.println( "<div align='center'><br/><fieldset style=width:90%><legend>个税计算器</legend><br/>");
out.println( "<form method='post' action='LifeCycleServlet'>");

out.println( "<div style='line'>");
out.println( " <div class='leftDiv'>您的工资为</div><div align='left' class='rightDiv'><input type='text' name='income'> 单位:元</div>");
out.println( "</div><br/>");

out.println( "<div style='line'>");
out.println( " <div class='leftDiv'></div><div align='left' class='rightDiv'><input type='submit' value=' 计算个税 ' class=button></div>");
out.println( "</div>");

out.println( "</form>");

out.println( "<BODY>");
out.println( "</BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}

/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to
* post.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doPost(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

this.log("执行 doPost() 方法 ... " );
response.setCharacterEncoding( "UTF-8");
response.setContentType( "text/html");
PrintWriter out = response.getWriter();
out.println( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println( "<HTML><HEAD><TITLE>个人所得税计算</TITLE></HEAD>" );
out.println( "<link rel='stylesheet' type='text/css' href='../css/style.css'>");
out.println( "<BODY>");

out.println( "<div align='center'><br/><fieldset style=width:90%><legend>个税计算器</legend><br/>");

try {
// 从参数中获取的工资数目
double income = new Double(request.getParameter("income" ));
// 应纳税部分
double charge = income - startPoint;
// 缴税
double tax = 0;

if (charge <= 0) {
tax = 0;
}
if (charge > 0 && charge <= 500) {
tax = charge * 0.05;
}
if (charge > 500 && charge <= 2000) {
tax = charge * 0.1 - 25;
}
if (charge > 2000 && charge <= 5000) {
tax = charge * 0.15 - 125;
}
if (charge > 5000 && charge <= 20000) {
tax = charge * 0.2 - 375;
}
if (charge > 20000 && charge <= 40000) {
tax = charge * 0.25 - 1375;
}
if (charge > 40000 && charge <= 60000) {
tax = charge * 0.30 - 3375;
}
if (charge > 60000 && charge <= 80000) {
tax = charge * 0.35 - 6375;
}
if (charge > 80000 && charge <= 100000) {
tax = charge * 0.4 - 10375;
}
if (charge > 100000) {
tax = charge * 0.45 - 15375;
}

out.println( "<div style='line'>");
out.println( " <div class='leftDiv'>您的工资为</div><div class='rightDiv'>"
+ income + " 元</div>");
out.println( "</div>");

out.println( "<div style='line'>");
out.println( " <div class='leftDiv'>您应纳税</div><div class='rightDiv'>"
+ tax + " 元</div>");
out.println( "</div><br/>");

out.println( "<input type='button' onclick='history.go(-1);' value='纳税光荣 逃税可耻 返回' class=button>");

} catch (Exception e ) {
out.println( "请输入数值类型数据。<input type='button' onclick='history.go(-1);' value='返回' class=button>");
}
out.println( "</BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}

@Override
public void destroy() {
// TODO Auto-generated method stub
this.log("执行 destroy() 方法 ... " );
startPoint = 0;
super.destroy();

}

运行的结果如下: Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术
控制台的输出: 十一月 04, 2015 9:14:06 下午 org.apache.catalina.startup.Catalina start INFO: Server startup in 1027 ms 十一月 04, 2015 9:14:07 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行init()方法.... 十一月 04, 2015 9:14:07 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行service()方法... 十一月 04, 2015 9:14:07 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行 doGet() 方法 ... 十一月 04, 2015 9:14:10 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行service()方法... 十一月 04, 2015 9:14:10 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行 doPost() 方法 ... 十一月 04, 2015 9:14:11 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行service()方法... 十一月 04, 2015 9:14:11 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行 doGet() 方法 ... 十一月 04, 2015 9:14:15 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行service()方法... 十一月 04, 2015 9:14:15 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行 doPost() 方法 ... 十一月 04, 2015 9:14:16 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行service()方法... 十一月 04, 2015 9:14:16 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行 doGet() 方法 ... 十一月 04, 2015 9:14:20 下午 org.apache.coyote.http11.Http11AprProtocol pause INFO: Pausing Coyote HTTP/1.1 on http-8080 十一月 04, 2015 9:14:20 下午 org.apache.coyote.ajp.AjpAprProtocol pause INFO: Pausing Coyote AJP/1.3 on ajp-8009 十一月 04, 2015 9:14:21 下午 org.apache.catalina.core.StandardService stop INFO: Stopping service Catalina 十一月 04, 2015 9:14:21 下午 org.apache.catalina.core.ApplicationContext log INFO: LifeCycleServlet: 执行 destroy() 方法 ... 十一月 04, 2015 9:14:21 下午 org.apache.catalina.core.ApplicationContext log INFO: SessionListener: contextDestroyed() 十一月 04, 2015 9:14:21 下午 org.apache.catalina.core.ApplicationContext log INFO: ContextListener: contextDestroyed() 十一月 04, 2015 9:14:21 下午 org.apache.coyote.http11.Http11AprProtocol destroy INFO: Stopping Coyote HTTP/1.1 on http-8080 十一月 04, 2015 9:14:21 下午 org.apache.coyote.ajp.AjpAprProtocol destroy INFO: Stopping Coyote AJP/1.3 on ajp-8009
3.8.3 注解@PostContruct @PreDestroy 两个注解用来修饰一个非静态的void方法,写在方法之前,或者void,返回类型前面
@PostContruct
public void someMethod(){
...
}
public @PreDestroy void anotherMethod(){
...
}
Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
注解影响服务器启动速度,服务器启动遍历web中WEB-INF/classes下的所有class文件,以及/lib下的所有jar文件,检查哪些使用了注解,如果不用可以在web.xml中设置metadata-complete为true
3.9 Servlet之间跳转 Servlet之间可以进行跳转。 现在的MVC框架都使用了Servlet跳转,三个独立模块:Model业务处理模块(负责处理业务),View视图模块(负责显示数据),Control控制模块(负责控制)。 在Struts框架中,三部分为3个Servlet,程序在3个Servlet之间跳转。
3.9.1 转向Forward 转向通过RequestDispatcher对象的forward方法实现。 如下: RequestDispatcher dispatcher = request.getRequestDispatcher( "/WEB-INF/web.xml"); dispatcher.forward(request , response ); getRequestDispatcher()参数必须以‘/’开始,'/'表示本web应用程序的根目录。
Forward是MVC框架中常用的技术,Forward不仅可以跳转到本应用的另一个Servlet,JSP页面,也可跳转到另外一个文件,设置WEb-INF文件夹下的文件。
使用向导,新建ForwardServlet.java
public class ForwardServlet extends HttpServlet {

/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

String destination = request.getParameter("destination" );

// 跳转到 /WEB-INF/web.xml。通过地址栏输入网址是不能访问到该文件的,但是 forward 可以
if ("file" .equals(destination )) {
RequestDispatcher dispatcher = request
.getRequestDispatcher( "/WEB-INF/web.xml");
dispatcher.forward(request , response );
}
// 跳转到 /forward.jsp
else if ("jsp" .equals(destination )) {
// 通过 setAttribute 方法传递一个 Date 对象给 JSP 页面
Date date = new Date();
request.setAttribute( "date", date );
RequestDispatcher dispatcher = request
.getRequestDispatcher( "/forward.jsp");
dispatcher.forward(request , response );
}
// 跳转到另一个 Servlet
else if ("servlet" .equals(destination )) {
RequestDispatcher dispatcher = request
.getRequestDispatcher( "/servlet/LifeCycleServlet");
dispatcher.forward(request , response );
} else {
response.setCharacterEncoding( "UTF-8");
response.setContentType( "text/html; charset=UTF-8");
response.getWriter().println(
"缺少参数。用法:" + request.getRequestURL()
+ "?destination=jsp 或者 file 或者 servlet ");
}
}
}

ForwardServlet根据地址栏传人的destination参数不同跳转不同的目的地,如果为file,跳转到/WEB-INF/web.xml;如果为servlet,跳转到LifeCycleServlet,如果jsp跳转到JSP页面,/forwa.jsp forward.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<jsp:directive.page import= "java.util.Date" />
<jsp:directive.page import= "java.text.SimpleDateFormat" />
<%
Date date = (Date) request.getAttribute( "date");
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD >
<TITLE> Forward 跳转</TITLE >
<link rel= 'stylesheet' type ='text/css'
href= '<%=request.getContextPath() %>/css/style.css'>
</HEAD >
<BODY >
<div align='center'>
<br />
<fieldset style=width :90%>
<legend>
Forward 跳转
</legend>
<br />
<div style=' line' >
<div class= 'leftDiv' style='width :250px; '>
从 ForwardServlet 中取到的 Date 为
</div>
<div align= 'left' class='rightDiv' >
<%=( new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS" ))
.format(date) %>
</div>
</div>
<br />
<div style=' line' >
<div align= "center">
<input type= 'button'
onclick= 'location="<%=request.getContextPath() %>/servlet/ForwardServlet?destination=servlet"; '
onmouseover="window.status=' <%=request.getContextPath() %>/servlet/ForwardServlet?destination=servlet'"
value= '跳转到 Servlet' class=button >
<input type= 'button'
onclick= 'location="<%=request.getContextPath() %>/servlet/ForwardServlet?destination=file"; '
onmouseover="window.status=' <%=request.getContextPath() %>/servlet/ForwardServlet?destination=file'"
value= '跳转到 web.xml' class=button >
<input type= 'button'
onclick= 'location="<%=request.getContextPath() %>/servlet/ForwardServlet?destination=jsp"; '
onmouseover="window.status=' <%=request.getContextPath() %>/servlet/ForwardServlet?destination=jsp'"
value= '跳转到 JSP' class=button >
</div>
</div>
</BODY >
</HTML>

键入地址,不加参数 Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 加参数: Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术
forward是最常用的方式,在struts、webwork等MVC框架中,都是用Servlet处理用户请求,结果通过request.setAttribute()放到request中,然后forward到JSP中显示。
3.9.2 重定向 重定向利用服务器返回的状态码来实现,服务器通过设置HttpServletResoponse的setStatus方法设置状态码。 Java Web学习笔记 3 深入Servlet技术 301 302都表示重定向,区别301永久性重定向,302临时性重定向。 Java Web学习笔记 3 深入Servlet技术
下面代码将访问该Servlet的请求重定向到另一个网址 response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);//设置状态码302 response.setHeader("Location",“http://www.hellodba.net”);
这个例子利用Servlet统计下载文件的下载次数。 RedirectServlet.java
public class RedirectServlet extends HttpServlet {

Map<String, Integer> map = new HashMap<String, Integer>();

@Override
public void init() throws ServletException {
map.put( "/download/setup.exe", 0);
map.put( "/download/application.zip", 0);
map.put( "/download/01.mp3", 0);
}

public void doGet(HttpServletRequest request , HttpServletResponse response )
throws ServletException, IOException {

// response.setHeader("Refresh","1000,URL=http://localhost:8080/servlet/index.jsp");
String filename = request.getParameter("filename" );

if (filename != null) {

int hit = map .get(filename );// 取下载次数
map.put( filename, ++ hit); // 下载次数 + 1 后保存
// 重定向到文件
response.sendRedirect( request.getContextPath() + filename);
} else {
response.setCharacterEncoding( "UTF-8");
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>文件下载</TITLE></HEAD>" );
out.println( " <link rel='stylesheet' type='text/css' href='../css/style.css'>");
out.println( " <BODY><br/>" );

out.println( "<fieldset align=center style=width:90%><legend>文件下载</legend>");
out.println( "<table width=100%>");
out.println( " <tr>");
out.println( " <td><b>文件名</b></td>" );
out.println( " <td><b>下载次数</b></td>" );
out.println( " <td><b>下载</b></td>" );
out.println( " </tr>");

for (Entry<String, Integer> entry : map.entrySet()) {
out.println( "<tr>");
out.println( " <td>" + entry .getKey() + "</td>");
out.println( " <td>" + entry .getValue() + "</td>");
out.println( " <td><a href='"
+ request.getRequestURI()
+ "?filename="
+ entry.getKey()
+ "' target='_blank' onclick='location=location; '>下载</a></td>");
out.println( "</tr>");
}

out.println( "</table>");
out.println( " </legend>");
out.println( " </BODY>");
out.println( "</HTML>");
out.flush();
out.close();
}
}

@Override
public void destroy() {
map = null;
}
}
Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术

3.9.3 自动刷新
response.setHeader("Refresh","1000,URL=http://localhost:8080/servlet/index.jsp");
其中1000 时间,单位毫秒,URL指定网址。
3.10 Servlet与线程安全 由于Servlet只会有一个实例,多个用户同时请求同一个Servlet时,Tomcat会派生出多线程执行Servlet的代码,因此Servlet有线程不安全的隐患。 ThreadSafetyServlet.java
public class ThreadSafetyServlet extends HttpServlet {

private String name;
@Override
protected void doGet(HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
name = req.getParameter( "name");
resp.setCharacterEncoding( "UTF-8");
resp.setContentType( "text/html");
try{
Thread. sleep(10000);
} catch(InterruptedException e ){}

resp.getWriter().println( "您好, "+ name +". 您使用了GET方式提交数据" );
}

//本例中不会调用dopost 方法
@Override
protected void doPost(HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
name= req.getParameter( "name");
resp.setCharacterEncoding( "UTF-8");
resp.getWriter().println( "您好, "+name +".您使用了POST方式提交数据" );
}
}

3.10.2 让doGet线程沉睡10s,但是显示的结果相同, Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术 Java Web学习笔记 3 深入Servlet技术 最后显示的结果却是相同的,原因就是后面一个执行的覆盖了前面的一个 Java Web学习笔记 3 深入Servlet技术
Java Web学习笔记 3 深入Servlet技术
解决的办法尽量不要使用那么属性,分别定义到方法中, 虽然使用synchronized(name)可以解决,但会造成线程等待也是不科学的。