Servlert基本程序架构: (FirstServlet.java + web.xml)
FirstServlet.java
package com.helloben.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class FirstServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { execute(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { execute(request, response); } @Override public String getServletInfo() { return "Short description"; } protected void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); request.setCharacterEncoding("UTF-8"); String requestUri = request.getRequestURI(); String method = request.getMethod(); String param = request.getParameter("param"); try (PrintWriter out = response.getWriter()) { out.println("<!DOCTYPE html>"); out.println("<html>"); out.println("<head>"); out.println("<title>Servlet FirstServlet</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>FirstServlet at " + request.getContextPath() + "</h1>"); out.println("以 " + method + " 方式访问该页面。取到的 param 参数为:" + param + "<br/><br/>"); out.println("<form action='" + requestUri + "' method='get'><input type='text' name='param' value=''><input type='submit' value='以 GET 方式访问 RequestServlet'></form>"); out.println("<br/><br/>"); out.println("<form action='" + requestUri + "' method='post'><input type='text' name='param' value=''><input type='submit' value='以 POST 方式访问 RequestServlet'></form>"); out.println("<br/><br/>"); out.println("<script>document.write('本页面最后更新时间:' + document.lastModified + '<br /><br/>'); </script>"); out.println("<script>document.write('本页面URL:' + location + '<br/>' ); </script>"); out.println("</body>"); out.println("</html>"); } } }
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>com.helloben.servlet.FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/FirstServlet</url-pattern> </servlet-mapping> <session-config> <session-timeout> 30 </session-timeout> </session-config> </web-app>
访问路径: http://localhost:8080/ch03servlet/FirstServlet
1. 获取request变量
String authType = request.getAuthType(); String localAddr = request.getLocalAddr(); Locale locale = request.getLocale(); String localName = request.getLocalName(); String contextPath = request.getContextPath(); int localPort = request.getLocalPort(); String method = request.getMethod(); String pathInfo = request.getPathInfo(); String pathTranslated = request.getPathTranslated(); String protocol = request.getProtocol(); String queryString = request.getQueryString(); String remoteAddr = request.getRemoteAddr(); int port = request.getRemotePort(); String remoteUser = request.getRemoteUser(); String requestedSessionId = request.getRequestedSessionId(); String requestURI = request.getRequestURI(); StringBuffer requestURL = request.getRequestURL(); String scheme = request.getScheme(); String serverName = request.getServerName(); int serverPort = request.getServerPort(); String servletPath = request.getServletPath(); Principal userPrincipal = request.getUserPrincipal(); String accept = request.getHeader("accept"); String referer = request.getHeader("referer"); String userAgent = request.getHeader("user-agent"); String serverInfo = this.getServletContext().getServerInfo();
2.生成图片验证码(IdentityServlet.java)
package com.helloben.servlet; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Random; import javax.servlet.*; import javax.servlet.http.*; public class IdentityServlet extends HttpServlet { public static final char[] CHARS = { '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', '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(); 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()); } protected void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("image/jpeg"); String randomString = getRandomString(); request.getSession(true).setAttribute("randomString", randomString); int width = 100; int height = 30; Color color = getRandomColor(); Color reverse = getReverseColor(color); BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = bufferedImage.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); } // 转成JPEG格式 ServletOutputStream out = response.getOutputStream(); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(bufferedImage); out.flush(); } }
3. 获取初始化变量
Enumeration params = this.getInitParameterNames(); while(params.hasMoreElements()){ String usernameParam = (String)params.nextElement(); String passnameParam = this.getInitParameter(usernameParam); }
4. 获取上下文变量
ServletContext servletContext = this.getServletConfig().getServletContext(); String uploadFolder = servletContext.getInitParameter("upload folder"); String allowedFileType = servletContext.getInitParameter("allowed file type");
5. 资源注入(InjectionServlet.java)
@Resource(name="hello") private String hello; @Resource(name="i") private int i; @Resource(name="persons") private String persons;
web.xml
<env-entry> <env-entry-name>persons</env-entry-name> <env-entry-type>java.lang.String</env-entry-type> <env-entry-value>HelloBen, Tony, Rose, Alix</env-entry-value> </env-entry>
6. 使用JNDI获取资源
Context ctx = new InitialContext(); String hello = (String)ctx.lookup("hello"); Integer i = (Integer)ctx.lookup("i"); String persons = (String)ctx.lookup("person");
7. 注射数据源
@Resource javax.sql.DataSource datasource; public Connection getConnection() throws SQLException{ Connection conn = datasource.getConnection(); return conn; }
8. GET方式提交表单(search.jsp)
<form action='SearchServlet' method='get'> <input type="radio" name="type" value="web" checked/>网页 <input type="text" name="word" value="" style="width:300px; "/> <input type="submit" value="用雅虎搜索" style="width:100px; "/> </form>
URL: http://server:8080/webapp/SearchServlet?type=web&word=wbsn
SearchServlet.java
String word = request.getParameter("word");
String type = request.getParameter("type");
9. POST方式提交表单(postPersonInfo.jsp)
<form action="PostServlet" method="POST"> <input type="text" name="name" class="text" /> <input type="password" name="password" class="text" /> </form>
PostServlet.java
String name = request.getParameter("name"); String password = request.getParameter("password"); String sex = request.getParameter("sex"); int age = 0; try { age = Integer.parseInt(request.getParameter("age")); } catch (Exception e) { } Date birthday = null; try { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); birthday = format.parse(request.getParameter("birthday")); } catch (Exception e) { } String[] interesting = request.getParameterValues("interesting"); String area = request.getParameter("area"); String description = request.getParameter("description"); String btn = request.getParameter("btn");
10. 上传文件
Web文件上传也采用POST方式。(upload.jsp)
<form action="UploadServlet" method="post" enctype="multipart/form-data"> <input type="file" name="file1" class="text"> </form>
上传文件时,浏览器以二进制方式发送数据。解析二进制数据需要类库,如SmartUpload与Apache Commons Fileupload。SmatUpload是商业类库,解析过程中数据存放在内存中,因此比较快,但是大文件时会内存溢出。
UploadServlet.java
File file1 = null; File file2 = null; String description1 = null; String description2 = null; // 使用 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(); }
11. 带进度条的文件上传
实时显示上传进度的原理是服务器在处理上传文件的同事,将上传进度的信息如文件总长度、已上传多少,传输速率等写入Session中。客户端浏览器利用Ajax技术再新开一个独立的线程从Session中获取上传进度信息,并实时显示。Session可以看做是服务器内存。
uploadprogress.jsp
<%@page language="java" contentType="text/html" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>上传文件</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> <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", "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> </head> <body> <iframe name=upload_iframe width=0 height=0></iframe> <form action="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> </form> </body> </html>
ProgressUploadServlet.java
package com.helloben.servlet.upload; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Iterator; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class ProgressUploadServlet extends HttpServlet { @Override protected 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(); long time = (currentTime - startTime) / 1000 + 1; double velocity = ((double) status.getBytesRead()) / (double) time; double totalTime = status.getContentLength() / velocity; double timeLeft = totalTime - time; int percent = (int) (100 * (double) status.getBytesRead() / (double) status.getContentLength()); double length = ((double) status.getBytesRead()) / 1024 / 1024; 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); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { UploadStatus status = new UploadStatus(); UploadListener listener = new UploadListener(status); request.getSession(true).setAttribute("uploadStatus", status); // Apache 上传工具 ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); 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()); } } @Override public String getServletInfo() { return "Short description"; } }
UploadListener.java
package com.helloben.servlet.upload; import org.apache.commons.fileupload.ProgressListener; public class UploadListener implements ProgressListener { private UploadStatus status; public UploadListener(UploadStatus status) { this.status = status; } @Override public void update(long bytesRead, long contentLength, int items) { status.setBytesRead(bytesRead); status.setContentLength(contentLength); status.setItems(items); } }
UploadStatus.java
package com.helloben.servlet.upload; class UploadStatus { private long bytesRead; private long contentLength; private int items; private long startTime = System.currentTimeMillis(); 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; } }
12. Servlet生命周期(init() --> service() --> destroy())
13. web.xml文件详解 (http://www.cnblogs.com/hellojava/archive/2012/12/28/2835730.html)