Servlet
Posted dreamhome
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet相关的知识,希望对你有一定的参考价值。
TestServlet.java
// 文件路径 D:\ApacheServer\web_java\HelloWorld\src\com\test\TestServlet.java package com.test; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.sql.SQLException; import java.sql.PreparedStatement; import java.text.SimpleDateFormat; import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.Multipart; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpSession; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.filefilter.SuffixFileFilter; import org.apache.commons.fileupload.FileUploadException; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; // 由于 web.xml 里配置的 url-pattern = /TomcatTest/TestServlet ,所以该 Servlet 浏览地址可以是 http://localhost:8080/TomcatTest/TestServlet // 下面的注解 @WebServlet 功能和 web.xml 配置 url-pattern 类似,所以该 Servlet 浏览地址也可以是 http://localhost:8080/TestServlet // 注解浏览地址和 web.xml 里配置的 url-pattern 地址不能一样,要么只配置其中一项(删除注解,或者删除web.xml中对应Servlet的<servlet-mapping>...</servlet-mapping>项),要么两者配置地址不能相同 @WebServlet("/TestServlet") public class TestServlet extends HttpServlet // 实际作用不明,暂时注释,无影响 //private static final long serialVersionUID = 1L; public TestServlet() super(); public void init() throws ServletException // 创建 Servlet 时只执行一次的 init public void destroy() // 销毁 Servlet 时只执行一次的 destroy // destroy 方法被调用后,servlet 被销毁,但是并没有立即被回收,再次请求时,并没有重新初始化。 // post 请求会被 doPost 处理 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException // 转移到 doGet 函数处理信息 doGet(request, response); // get 请求会被 doGet 处理 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException //response.getWriter().append("Served at1: ").append(request.getContextPath()); /* // 配合测试异常处理 Servlet (这里是 TestErrorServlet )捕获处理 web 容器抛出的异常 if(true) response.setContentType("text/html;charset=UTF-8"); throw new ServletException("这是测试异常信息"); */ // ============================= response 响应 ============================================ // 设置返回响应内容类型及编码,否则返回输出中文会乱码 response.setContentType("text/html;charset=UTF-8"); // 添加一个自定义名称和值的响应报头。 response.setHeader("test_foo", "test_val"); // 响应返回任意错误响应状态码及信息(通常为404 或407等状态码),该设置会使页面直接显示错误页面 //response.sendError(404,"test response status"); // 返回任意响应状态码 //response.setStatus(200); // 生成一个 302 响应,暂时性重定向到后面的网址 //response.sendRedirect("http://www.baidu.com"); // ============================= 请求的 HTTP 头信息 ============================================ // 获取打印客户端请求的 HTTP 头信息 Enumeration headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) String paramName = (String)headerNames.nextElement(); String paramValue = request.getHeader(paramName); response.getWriter().append("<br/>客户端请求的 HTTP 头信息 : " + paramName + " 值为 : " + paramValue); // ============================= Servlet Cookie ============================================ // Servlet Cookie 处理需要对中文进行编码与解码,方法如下 String enStr = java.net.URLEncoder.encode("测试中文", "UTF-8"); // 编码 String deStr = java.net.URLDecoder.decode(enStr, "UTF-8"); // 解码 // 创建新 cookie 对象 并赋键值对,键值即该 cookie 名称,这里值赋中文值,需要先编码 Cookie cookie = new Cookie("testKey",enStr); // 设置 cookie 适用的域名,例如 runoob.com cookie.setDomain("runoob.com"); // 获取 cookie 适用的域,例如 runoob.com cookie.getDomain(); // 设置 cookie 过期的时间(以传给客户端为起始,以秒为单位)。如果不设置,cookie 只会在当前 session 会话中持续有效。或者cookie.setMaxAge(0) 即表示删除这个cookie cookie.setMaxAge(3600 * 24); // 返回 cookie 的最大生存周期(以秒为单位),默认情况下,-1 表示 cookie 将持续下去,直到浏览器关闭。 cookie.getMaxAge(); // 返回 cookie 的名称。名称在创建后不能改变。 cookie.getName(); // 设置 cookie 的值,除了创建 cookie 对象时赋值,setValue() 方法也可赋值。赋的值非中文就不用转码了 cookie.setValue("newTestVal"); // 获取 cookie 的值 cookie.getValue(); // 设置 cookie 适用的路径uri。浏览器在发该 cookie 消息给服务器之前,请求的 url 中必须存在一个指定 uri 路径。这个比较是通过将 path 属性值与请求的 url 从头开始逐字符串比较完成的。如果字符匹配,则发送该 cookie 消息。如果不指定路径,与当前页面相同目录(uri)下的(包括子目录下的)所有 url 浏览器都会返回 cookie。 cookie.setPath("/testuri"); // 获取 cookie 适用的路径uri。 cookie.getPath(); // 设置布尔值,表示 cookie 是否应该只在加密的(即 SSL)连接上发送。 cookie.setSecure(false); // 设置该 cookie 在浏览器中不能通过 javascript 的 document.cookie 属性访问 cookie.setHttpOnly(true); // 设置cookie的注释。该注释在浏览器向用户呈现 cookie 时非常有用。 cookie.setComment("testNotes"); // 获取 cookie 的注释,如果 cookie 没有注释则返回 null。 cookie.getComment(); // 输出 cookie值,中文的话需要解码 response.getWriter().append("<br/>cookie testKey 值为 : " + java.net.URLDecoder.decode(cookie.getValue(), "UTF-8")); // 发送 Cookie 到 HTTP 响应头,即将 cookie 传到浏览器 response.addCookie(cookie); // 获取览器发送的与当前页面 url 相关的 Cookie 的数组 Cookie request_cookie[] = request.getCookies(); if( request_cookie != null ) // 遍历获取每一个浏览器发送的 cookie for (int i = 0; i < request_cookie.length; i++) cookie = request_cookie[i]; // 对比找到指定名称的 cookie if((cookie.getName( )).compareTo("delCookieName") == 0 ) // 然后删除 cookie.setMaxAge(0); response.addCookie(cookie); else response.getWriter().append("<br/>浏览器上传 cookie 名称 : " + cookie.getName() + " 值为 : " + cookie.getValue()); else response.getWriter().append("<br/>No Cookie founds"); // ============================= Servlet Session ============================================ // 获取当前请求的 session 会话,需要在向客户端发送任何文档内容之前调用 request.getSession()。 // getSession() 等同于 getSession(true) 若存在会话,则返回该会话,否则新建一个会话。getSession(false) 则是如存在会话,则返回该会话,否则返回NULL HttpSession session = request.getSession(); //下面总结了 HttpSession 对象中可用的几个重要的方法: // 指定键名绑定一个对象到该 session 会话,绑定的对象可以是任意类型的对象包括字符串 Object anyObject = new Object(); session.setAttribute("testKey", anyObject); // 获取 session 中指定键名的数据值,如果没有指定该键名对则返回 null,之前赋的键值无论何类型,getAttribute 方法返回的都是 Object 类型,使用时需要强制类型 Object val = session.getAttribute("testKey"); // 从该 session 会话移除指键名称及对应对象。 session.removeAttribute("testKey"); // 以枚举方式获取 session 中所有设置绑定的键名 Enumeration sessionEnumeration = session.getAttributeNames(); // 获取 session id String sessionId = session.getId(); // 返回该 session 创建的时间戳,单位毫秒,创建完不一定已经回传给客户端。 long sessionBegin = session.getCreationTime(); // 判断该对话是否是第一次建立,即客户端还未保存 session id,或者客户选择不参入该 session 会话,则该方法返回 true boolean isNew = session.isNew(); // 返回该 session 客户端最后一次请求到服务器的时间戳,单位毫秒 long sessionEnd = session.getLastAccessedTime(); // 设定 session 在用户请求间隔多少秒内不失效 session.setMaxInactiveInterval(360); // 返回 Servlet 容器 session 在用户请求间隔多少秒内不失效 int interval = session.getMaxInactiveInterval(); // 使该 session 会话无效,并解除绑定到它上面的任何对象。 //session.invalidate(); // 输出相关信息 // session 创建时间 Date createTime = new Date(sessionBegin); // 该网页的最后一次访问时间 Date lastAccessTime = new Date(sessionEnd); //设置日期输出的格式 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 设置键值 String testStr = ""; int testInt = 0; if(session.getAttribute("key_str") == null) testStr = "this is test str"; session.setAttribute("key_str", testStr); else testStr = (String)session.getAttribute("key_str"); if(session.getAttribute("key_int") == null) testInt = 0; session.setAttribute("key_int", testInt); else testInt = (int)session.getAttribute("key_int") + 1; session.setAttribute("key_int", testInt); response.getWriter().append("<br/>用户最后一次请求时间为 : " + dateFormat.format(lastAccessTime)); response.getWriter().append("<br/>session key_str 键对应值为 : " + testStr); response.getWriter().append("<br/>session testInt 键对应值为 : " + testInt); /* // ============================= 下载文件 ============================================ // 最好放在 response 所有输出之前调用 this.download(response); // 为禁止再向浏览器发送其他输出流 if(true) return; */ // ============================= 连接 mysql ============================================ this.conn_mysql(response); // ============================= 日期处理 ============================================ doDate(response); // ============================= 网页重定向 ============================================ // 浏览器重新请求的新地址,URL会变 String location = "https://www.baidu.com" ; // 方法一 //response.sendRedirect(location); // 方法二 //response.setStatus(response.SC_MOVED_TEMPORARILY); //response.setHeader("Location", location); // ============================= 自动刷新页面 ============================================ // 设置自动刷新间隔为 5 秒 //response.setIntHeader("Refresh", 5); // ============================= 发送邮件 ============================================ sendMail(request, response); // 获取 form-data 类型 post 数据依赖于 FileUpload,下载地址 http://commons.apache.org/proper/commons-fileupload/ 这里用到的是 FileUpload 1.4 选择 Binaries->commons-fileupload-1.4-bin.zip // FileUpload 依赖于 Commons IO,下载地址 http://commons.apache.org/proper/commons-io/ 这里用到的是 Commons IO 2.6 选择 Binaries->commons-io-2.6-bin.zip // 将下载的压缩包内的 commons-io-2.6.jar 和 commons-fileupload-1.4.jar 解压缩到 D:\ApacheServer\web_java\HelloWorld\WebContent\WEB-INF\lib 中。环境变量 CLASSPATH 补充 ";D:\ApacheServer\web_java\HelloWorld\WebContent\WEB-INF\lib\commons-io-2.6.jar;D:\ApacheServer\web_java\HelloWorld\WebContent\WEB-INF\lib\commons-fileupload-1.4.jar;" 。eclipse->Java Build Path 中分别引入 commons-io-2.6.jar 与 commons-fileupload-1.4.jar // 检测是 GET 和 x-www-form-urlencode POST 还是 multipart/form-data POST 方式 if (!ServletFileUpload.isMultipartContent(request)) // 提交的表单类型为GET 或者 x-www-form-urlencoded 方式的 POST getOrFormUrlencoded(request, response); else // 提交的表单类型为 multipart/form-data 的 POST formData(request, response); // 自建方法,文件下载 public void download(HttpServletResponse response) try // 要下载的文件名,必须是服务器上存在的文件,eclipse 实际运行项目路径需要找找 // 这里实际目录为 D:/ApacheServer/web_java/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/HelloWorld/upload/00125943U-0.jpg String fileName = "00125943U-0.jpg"; // 文件下载到客户端时文件名 String downName = "download.jpg"; // 设置文件 MIME 类型,getServletContext()为父类方法 response.setContentType(this.getServletContext().getMimeType(fileName)); // 设置 Content-Disposition 响应报头,命名下载文件名称 response.setHeader("Content-Disposition"," attachment;filename=" + downName); ServletContext context = this.getServletContext(); // 根据文件在项目中的路径获取文件的完整绝对路径,这里 upload 文件夹为项目根目录下,与 WEB-INF 文件夹同级父目录下 String fullFileName = context.getRealPath("/upload/" + fileName); // 把文件读入到内存输入流中 InputStream inputStream = new FileInputStream(fullFileName); // 创建输出流对象 ServletOutputStream outputStream = response.getOutputStream(); // 每次从输入流实际读取到的字节数 int len = 0; // 定义一个字节数组,相当于缓存,数组长度为1024,即缓存大小为1024个字节 byte[] cache = new byte[1024]; // inputStream.read(cache)) 方法,从输入流中读取最多 cache 数组大小的字节,并将其存储在 cache 中。以整数形式返回实际读取的字节数,当文件读完时返回-1 while((len = inputStream.read(cache)) != -1) // 每次把数组 cache 从 0 到 len 长度的内容输出到浏览器 outputStream.write(cache, 0, len); // 关闭流 inputStream.close(); outputStream.close(); catch(Exception exception) // 处理 Class.forName 错误 exception.printStackTrace(); // 自建方法,连接 MySQL 数据库 public void conn_mysql(HttpServletResponse response) // 需要下载 MySQL 驱动 jar 包,下载地址 https://mvnrepository.com/artifact/mysql/mysql-connector-java,这里用到的是 mysql-connector-java-8.0.17.jar,下载的 jar 包 要放在 Tomcat 安装目录下的 lib 文件夹内,这里路径是 D:\ApacheServer\apache-tomcat\lib\mysql-connector-java-8.0.17.jar // 连接 MySQL 需要 MySQL 的时区和 java 一致(MySQL 默认 UTC 时区),这里本地是北京时区。修改 MySQL 配置文件 my.ini 在 [mysqld] 项下添加一行 default-time-zone = ‘+8:00‘ 重启 MySQL 即可。如果不能修改MySQL配置文件,则将如下 jdbc:mysql://localhost:3306/testdb 改为 jdbc:mysql://localhost:3306/testdb?serverTimezone=UTC 亦可 try // 注册 JDBC 驱动器 // 如果下载的 MySQL jar 包是 5 系列版本,则需要用 com.mysql.jdbc.Driver 注册驱动,而且必须写 //Class.forName("com.mysql.jdbc.Driver"); // MySQL jar包 6 以上版本用 com.mysql.cj.jdbc.Driver 注册,或者不写也可,这里没有写,已注释掉 //Class.forName("com.mysql.cj.jdbc.Driver"); // 打开一个连接 Connection conn = null; // localhost 为数据库连接地址,3306 端口号,testDB 为数据库名称 String db_host = "jdbc:mysql://localhost:3306/testdb"; // 用户名 String user = "root"; // 密码 String password = "123456"; conn = DriverManager.getConnection(db_host,user,password); // ==================================================== Statement 类处理 // Statement 对象执行查询 SQL 语句 Statement statement = conn.createStatement(); String sql_sel = "SELECT id, name, age FROM test_table"; ResultSet result = statement.executeQuery(sql_sel); //遍历结果集 int i = 1; while(result.next()) int id = result.getInt("id"); String name = result.getString("name"); int age = result.getInt("age"); response.getWriter().append("<br/>第 " + i + "行 id : " + id + " name : " + name + " age : " + age); i++; // ==================================================== PreparedStatement 类处理 // PreparedStatement 执行插入语句效果更好,原因:1可以写动态参数化的查询,2PreparedStatement比 Statement 更快,3PreparedStatement可以防止SQL注入式攻击 // preparedStatement对象的 executeUpdate() 方法可执行 insert,update,delete 语句以及 SQL DDL(如建表,改表,删除表等), executeQuery() 方法执行select语句,execute()执行所有语句,效率也最慢 // ============================ executeUpdate 方法 //编写预处理 SQL 语句 String sql_ins= "INSERT INTO `test_table`(id, name, age) VALUES(?, ?, ?)"; PreparedStatement preparedStatement = conn.prepareStatement(sql_ins); preparedStatement.setInt(1, 3); //插入表数据的 id preparedStatement.setString(2, "testName"); // 名称 preparedStatement.setInt(3, 40); // 年龄 // 返回值是一个整数,指示受影响的行数(即更新计数)建表,删表等不操作行的语句总返回 0。 int updateCount = preparedStatement.executeUpdate(); response.getWriter().append("<br/> 插入结果 " + updateCount); // ============================ executeQuery 方法 // 执行 select 语句 preparedStatement = conn.prepareStatement(sql_sel); // 获取查询结果,result 遍历查询结果与之前 Statement 类方式一致 result = preparedStatement.executeQuery(); // ============================ execute 方法 preparedStatement = conn.prepareStatement(sql_sel); // execute 可用于执行任何SQL语,返回一个 boolean 值,如果执行后第一个结果(有可能返回的是多个结果集合)是 ResultSet(即查询语句结果),则返回 true,否则返回 false。 boolean isResult = preparedStatement.execute(); // 如果 execute() 执行的 sql 语句能返回多个结果集合时,PreparedStatement 对象获取下个 getResultSet() 或者 getUpdateCount() 前要先执行 getMoreResults() 使指针下移,然后再执行 getResultSet() 或 getUpdateCount() 获取当前指针指向结果 //preparedStatement.getMoreResults(); // 一至多个结果集时,获取第一个结果时不需要执行此语句,获取下一个结果时才执行,如在 while 循环语句里用 if(isResult) // 如果结果集当前指针指向的返回结果是个 select 查询结果,用 getResultSet 获取,如果执行的是更新语句,则返回的是更新计数,这时就要用 getUpdateCount来获取 result = preparedStatement.getResultSet(); // ... else //当某个过程返回两个更新计数,则首先调用方法getUpdateCount() updateCount = preparedStatement.getUpdateCount(); response.getWriter().append("<br/> 插入结果 " + updateCount); // 完成后关闭 preparedStatement.close(); result.close(); statement.close(); conn.close(); catch(SQLException sqlException) // 处理 JDBC 错误 sqlException.printStackTrace(); catch(Exception exception) // 处理 Class.forName 错误 exception.printStackTrace(); // 自建方法,处理日期 public void doDate(HttpServletResponse response) throws ServletException, IOException Date date = null; // 构造函数初始化当前日期和时间的对象 date = new Date(); // 或者构造指定日期时间的对象。参数为毫秒时间戳,示例时间为 2019/8/18 16:12:56 date = new Date(1566115976000L); // date 对应的时间戳大于 after() 的参数所对应时间戳则返回 true,否则返回 false。这里返回 false if(date.after(new Date())) response.getWriter().append("<br/> date对应时间大于 after 参数对应时间"); else response.getWriter().append("<br/> date对应时间小于 after 参数对应时间"); // 判断方式与 date.after() 相反 boolean isBefore = date.before(new Date()); // 克隆一个时间对象,但返回值类型为 Object Object objDate = date.clone(); // 如果两个 date 对象时间戳相等,返回0,如果 date 大于 compareTo() 里参数的时间,则返回正数,否则返回负数,这里结果为 -1 int compare = date.compareTo(new Date()); response.getWriter().append("<br/> 对比时间结果为 : " + compare); // 两日期对象对应时间戳相等返回 true,否则返回 false,这里返回 true boolean equals = date.equals(new Date(1566115976000L)); // 获取当前 date 对应时间戳 long stampLong = date.getTime(); response.getWriter().append("<br/> 当前 date 时间戳为 : " + stampLong); // 返回该日期对象的哈希码值 int hashCode = date.hashCode(); // 设置 date 对象对应的时间戳 date.setTime(1566119343000L); // 将 date 对象转换为字符串,这里返回为 Sun Aug 18 17:09:03 CST 2019 String strDate = date.toString(); response.getWriter().append("<br/> 当前 date 字符串为 : " + strDate); // 创建日期格式化对象,y 年,M 月,d 月中第几日,H 小时(24制),h 小时(12制), m 分,s 秒,S 毫秒,E 星期几,D 年中第几日,F 月中第几周,w 年中第几周,W 月中的第几周,a 上午下午,k 天中第几小时,K 带有 A.M./P.M. 的小时(0~11),z 时区 SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); String strFormat = dateFormat.format(date); // 这里输出日期为 2019-08-18 17:09:03 response.getWriter().append("<br/> 格式化后时间为 : " + strFormat); // 自建方法,发送邮件 public void sendMail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException // 需要先下载 javax.mail.jar 和 activation.jar。只发文字邮件 javax.mail.jar 就够了,发附件则还需要 activation.jar // mail.jar 下载地址 https://www.oracle.com/technetwork/java/javamail/index.html 点击 Downloads 下载 JavaMail API 1.4.7,或者 https://javaee.github.io/javamail/ 下载 JavaMail 1.6.2 这里版本是 JavaMail 1.6.2 // jaf 下载页面 https://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-plat-419418.html 这里用到版本 JavaBeans Activation Framework 1.1.1 // 提取下载的压缩包里的 javax.mail.jar 和 activation.jar 放到项目中 // 收件人的电子邮件 ID String to = "32705317@qq.com"; // 发件人的电子邮件 ID String from = "zdy_521@126.com"; // SMTP服务器地址 String host = "smtp.126.com"; // 授权密码 String passWord = "87477zhang"; // 设置邮件发送相关属性 Properties properties = System.getProperties(); // 设置邮件传输采用的协议smtp(这里使用网易的smtp服务器) properties.setProperty("mail.transport.protocol", "smtp"); //设置发送邮件的邮件服务器的属性 properties.setProperty("mail.smtp.host", host); //需要经过授权,也就是有户名和密码的校验,这样才能通过验证(一定要有这一条) properties.setProperty("mail.smtp.auth", "true"); // SMTP 服务器的端口 (非 SSL 连接的端口一般默认为 25, 可以不添加, 如果开启了 SSL 连接, // 需要改为对应邮箱的 SMTP 服务器的端口, 具体可查看对应邮箱服务的帮助, // QQ邮箱的SMTP(SLL)端口为465或587, 其他邮箱自行去查看) /* final String smtpPort = "465"; properties.setProperty("mail.smtp.port", smtpPort); properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); properties.setProperty("mail.smtp.socketFactory.fallback", "false"); properties.setProperty("mail.smtp.socketFactory.port", smtpPort); */ // 获取默认的 Session 对象 Session session = Session.getDefaultInstance(properties); // 会话采用debug模式 session.setDebug(true); try // 创建邮件对象 MimeMessage message = new MimeMessage(session); // 设置发送邮件地址,param1 代表发送地址 param2 代表发送的名称(任意的) param3 代表名称编码方式 message.setFrom(new InternetAddress(from, "发件人名称", "utf-8")); // 代表收件人 message.setRecipient(Message.RecipientType.TO, new InternetAddress(to, "收件人名称", "utf-8")); // To: 增加更多收件人(可选) //message.addRecipient(MimeMessage.RecipientType.TO, new InternetAddress("chimuhuadao@126.com", "收件人名称", "UTF-8")); //message.addRecipient(MimeMessage.RecipientType.TO, new InternetAddress("chimuhuadao@163.com", "收件人名称", "UTF-8")); // Cc: 抄送(可选) //message.setRecipient(MimeMessage.RecipientType.CC, new InternetAddress("chimuhuadao@126.com", "抄送人名称", "UTF-8")); // Bcc: 密送(可选) //message.setRecipient(MimeMessage.RecipientType.BCC, new InternetAddress("chimuhuadao@126.com", "密送人名称", "UTF-8")); // 设置邮件主题 message.setSubject("测试转发邮件"); //====================附件测试开始================= //以下部分为测试邮件附件,如不需要可以把整段附件这部分代码注释 // 创建 Multipart 对象,来包含邮件的多部分(正文,附件等)消息 Multipart multipart = new MimeMultipart(); // 第一部分正文消息部分 BodyPart bodyPart = new MimeBodyPart(); // 设置邮件正文内容 bodyPart.setContent("<h1>早安,世界</h1>", "text/html;charset=utf-8"); // 将正文消息部分添加到 Multipart 对象中 multipart.addBodyPart(bodyPart); // 第二部分是附件 bodyPart = new MimeBodyPart(); // 读取项目根目录下 upload 文件夹内 00125943U-0.jpg 文件作为附件,这里路径为 D:\ApacheServer\web_java\HelloWorld\WebContent\\upload\00125943U-0.jpg。这里WebContent为实际项目运行根目录 String fileName = "00125943U-0.jpg"; String filePath = request.getServletContext().getRealPath("./") + "upload" + File.separator + fileName; DataSource dataSource = new FileDataSource(filePath); bodyPart.setDataHandler(new DataHandler(dataSource)); // 设置邮件中附件名称 bodyPart.setFileName("testAttachment.jpg"); // 将附件部分添加到 Multipart 对象中 multipart.addBodyPart(bodyPart); //response.getWriter().append(filePath);if(true)return; // 另一份附件,可发送多个附件 bodyPart = new MimeBodyPart(); // 读取项目根目录下 upload 文件夹内 00125943U-0.jpg 文件作为附件 fileName = "abc.ppt"; filePath = request.getServletContext().getRealPath("./") + "upload" + File.separator + fileName; dataSource = new FileDataSource(filePath); bodyPart.setDataHandler(new DataHandler(dataSource)); // 设置邮件中附件名称 bodyPart.setFileName("testAttachment.ppt"); // 将附件部分添加到 Multipart 对象中 multipart.addBodyPart(bodyPart); //和下面发送文本的 message.setContent("<h1>早安,世界</h1>", "text/html;charset=utf-8"); 二选一执行 message.setContent(multipart); //====================附件测试结束================= // 设置邮件内容,可以带HTML标签,也可以不带,内容大小不限 //message.setContent("<h1>早安,世界</h1>", "text/html;charset=utf-8"); // 设置发送时间 message.setSentDate(new Date()); // 保存上面的编辑内容 message.saveChanges(); Transport transport = session.getTransport(); // 链接邮件服务器 transport.connect(from, passWord); // 发送信息 transport.sendMessage(message, message.getAllRecipients()); // 关闭链接 transport.close(); catch(Exception exception) // 处理错误 exception.printStackTrace(); // 自建方法,用来处理 GET URL 或 application/x-www-form-urlencoded 方式的 POST protected void getOrFormUrlencoded(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException // getParameter,getParameterNames 只能获取 get 参数(POST 请求里也能用 getParameter 获取 GET 参数)或者编码格式为 application/x-www-form-urlencoded 的 post 数据,无法获取 multipart/form-data 的 post 数据 // application/x-www-form-urlencoded 传的 post 数据实际和 get 方式一样,都是格式化成 参数1=值1&参数2=值2&参数3=值3&... ,区别是 get 参数在 url 中,post 参数在请求体里。 String name_val = request.getParameter("name"); response.getWriter().append("<br/>表单名 : name 单一值为 : " + name_val); // getParameterNames() 方法获取所有提交的表单参数名。该方法返回一个枚举对象,包含未指定顺序的参数名 Enumeration paramNames = request.getParameterNames(); // hasMoreElements() 循环遍历判断该枚举是否有更多元素,指针每次往后移一位 while(paramNames.hasMoreElements()) // nextElement() 每次获取该枚举一个元素,指针每次往后移一位 String paramName = (String)paramNames.nextElement(); // 根据参数名获取对应参数值,但不知道该参数名对应单个值还是多个值(复选框即是多个表单同名,不同值,与php不同JAVA相同复选框名后面不用加中括号 [] ),所以用数组接收 String paramValues[] = request.getParameterValues(paramName); // 读取参数值的数据 if (paramValues.length == 1) // 该参数名对应单一参数值 // 参数值为 paramValues[0] String paramValue = paramValues[0]; if (paramValue.length() > 0) // 判断该参数值有实际字符串内容 response.getWriter().append("<br/>表单名 : " + paramName + "单一值为 : " + paramValue); else // 读取多个值的数据 for(int i=0; i < paramValues.length; i++) // 值为 paramValues[i] response.getWriter().append("<br/>多重参数名 : " + paramName + "多重id值 : "+i+"为 : " + paramValues[i]); // 自建方法,用来处理 multipart/form-data 方式的 POST,若不想方法名后面跟 throws 抛出异常,则需在方法内执行有可能抛出异常的语句时有 try catch 捕获异常 protected void formData(HttpServletRequest request, HttpServletResponse response) try // 创建磁盘文件项目工厂(form-data方式POST获取参数必须用的不管有无上传文件),可设置限制上传文件的临时存储目录等 DiskFileItemFactory factory = new DiskFileItemFactory(); // 可有可无,setSizeThreshold方法判断post数据(包括上传文件及表单数据)的大小(以字节为单位的int值,大于该值则post数据以临时文件形式存在磁盘,小于等于此值则存在内存中),如果从没有调用该方法设置此临界值,将会采用系统默认值10KB。对应的getSizeThreshold() 方法用来获取此临界值。 //factory.setSizeThreshold(1024 * 1024 * 3); // 3MB // 可有可无,设置当上传数据大于 setSizeThreshold 设置的值时,临时文件在磁盘上的存放目录。当从没有此方法设置临时文件存储目录时,采用系统默认的临时文件路径 Tomcat 系统默认临时目录为 tomcat安装目录/temp/,默认的临时文件路径可通过 System.getProperty("java.io.tmpdir");查看 //factory.setRepository(new File(System.getProperty("java.io.tmpdir"))); // 通过文件工厂对象创建上传对象,可设置 post 文件最大上传大小,请求数据最大值(包含文件和表单数据)等 ServletFileUpload upload = new ServletFileUpload(factory); // 可有可无,设置上传的单个文件的最大字节数为100M //upload.setFileSizeMax(1024 * 1024 * 100); // 可有可无,设置整个表单的最大字节数为1G (包含文件和表单数据) //upload.setSizeMax(1024 * 1024 * 1024); // 可有可无,中文处理,解决上传数据的中文乱码 //upload.setHeaderEncoding("UTF-8"); // 构造路径存储上传的文件,request.getServletContext().getRealPath("./") 获取的路径 为 WEB-INF 文件夹父级目录,即项目根目录路径,这里路径为 D:\ApacheServer\web_java\HelloWorld\WebContent\\upload\00125943U-0.jpg。这里WebContent为实际项目运行根目录 String uploadPath = request.getServletContext().getRealPath("./") + "upload"; // 如果目录不存在则创建,目录同样只能一级一级创建,不能一次创建多级 File uploadDir = new File( uploadPath ); if (!uploadDir.exists()) uploadDir.mkdir(); // List类传泛型 FileItem 则其创建对象内元素都变为 FileItem 类型 // 将用户请求传给设置好参数的上传对象,返回一个数组 List<FileItem> item_list = upload.parseRequest(request); // 创建 param_map 保存提交表单的键值对 Map param_map = new HashMap(); // 假设有未知个数同表单名的复选框表单提交信息,用 testCheckBox 存该复选框选中的值 Map testCheckBox = new HashMap(); if (item_list != null && item_list.size() > 0) // 遍历上传的表单元素 for(FileItem fileItem : item_list) // fileItem.getFieldName() 表单参数名 String fieldName = fileItem.getFieldName(); // fileItem.getString("UTF-8") 获取表单参数的值,或者上传文件的文本内容 String fieldVal = fileItem.getString("UTF-8"); // 如果页面编码是 UTF-8 的 // 处理在表单中的字段 if (fileItem.isFormField()) response.getWriter().append("<br/>表单参数名 : " + fieldName + " 参数值为 : " + fieldVal); // 当表单名为 testCheckBox 时,将其不确定个数的多个值存到 Map 对象中 if(fieldName.equals("testCheckBox")) testCheckBox.put(testCheckBox.size(), fieldVal); // 把post参数以键值对形式重新存到 param_map 列表中。复选框的话最后一个选中的同名值会覆盖之前的值 param_map.put(fieldName, fieldVal); // 处理表单中上传文件,这里上传文件的表单名任意都可上传 if (!fileItem.isFormField()) // ===============上传文件 // 获取上传的文件名(含扩展名),fileItem.getName()只能获取上传文件的完整名,不能获取其他post表单参数值 String fileName = fileItem.getName(); // 拼接将文件保存本地完整路径及文件+扩展名。File.separator 表示目录分割斜杠 String filePath = uploadPath + File.separator + fileName; // 将合成的完整路径文件名 filePath 放入 File 对象中,File 对象代表磁盘中实际存在的文件和目录 File saveFile = new File(filePath); // 限制上传文件扩展名 String suffix_limit[] = ".html", ".jpg", ".jsp"; SuffixFileFilter filter = new SuffixFileFilter(suffix_limit); boolean flag = filter.accept(saveFile); if(!flag) response.getWriter().append("<br/>上传文件类型不符,文件名为 : " + fileName); return; // 将该上传文件按指定路径保存文件到硬盘 fileItem.write(saveFile); request.setAttribute("message", "文件上传成功!"); // 可以使用 param_map.get 获取表单参数值了 String name_val = (String) param_map.get("name"); response.getWriter().append("<br/>表单name的值 : " + name_val); // 遍历获取复选框的 Map 对象里每个值 for(int i = 0;i<testCheckBox.size();i++) response.getWriter().append("<br/>复选框i : " + i + "对应值 : " + (String) testCheckBox.get(i)); catch (FileUploadException fex) fex.printStackTrace(); catch (Exception ex) request.setAttribute("message", "错误信息: " + ex.getMessage());
TestFilter.java
// 文件路径 D:\ApacheServer\web_java\HelloWorld\src\com\test\TestFilter.java package com.test; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; // 浏览器暂不能通过 http://localhost:8080/HelloWorld/TestFilter 访问页面 @WebFilter("/TestFilter") //实现 Filter 类 public class TestFilter implements Filter public TestFilter() // Servlet容器在销毁 Filter 实例前调用该方法,在该方法中释放 Filter 实例占用的资源。 public void destroy() // TODO Auto-generated method stub // 该方法完成实际的过滤操作,当客户端请求过滤器设置的 URL 时,Servlet 容器将先调用过滤器的 doFilter 方法。FilterChain 用户访问后续过滤器。 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException // 这里的 request 和 response 对象与 Servlet 类中一样可获取用户请求信息及直接返回响应信息 // pass the request along the filter chain // 把请求传回过滤链 chain.doFilter(request, response); // web 容器启动时,web 服务器将创建 Filter 的实例对象,并调用其 init 方法,读取 web.xml 配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作( filter 对象只会创建一次,init 方法也只会执行一次)。开发人员通过 init 方法的参数,可获得代表当前 filter 配置信息的 FilterConfig 对象。 public void init(FilterConfig fConfig) throws ServletException // 获取初始化参数 String testParam = fConfig.getInitParameter("testParam"); // 输出初始化参数 System.out.println("web.xml 配置 测试参数 testParam 值为 : " + testParam); // Console 信息界面会出现 web.xml 配置 测试参数 testParam 值为 : 测试配置参数值 信息
TestErrorServlet.java
// 文件路径 D:\ApacheServer\web_java\HelloWorld\src\com\test\TestErrorServlet.java package com.test; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/TestErrorServlet") public class TestErrorServlet extends HttpServlet private static final long serialVersionUID = 1L; public TestErrorServlet() super(); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException //response.getWriter().append("Served at: ").append(request.getContextPath()); // javax.servlet.error.status_code 该属性给出状态码,状态码可被存储,并在存储为 java.lang.Integer 数据类型后可被分析 Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); // javax.servlet.error.request_uri 该属性给出报错页面的请求地址,可被存储,并在存储为 java.lang.String 数据类型后可被分析 String requestUri = (String) request.getAttribute("javax.servlet.error.request_uri"); // javax.servlet.error.message 该属性给出确切错误消息信息,信息可被存储,并在存储为 java.lang.String 数据类型后可被分析 String message = (String) request.getAttribute("javax.servlet.error.message"); // javax.servlet.error.servlet_name 该属性给出报错的 Servlet 类名,可被存储,并在存储为 java.lang.String 数据类型后可被分析 String servletName = (String) request.getAttribute("javax.servlet.error.servlet_name"); // javax.servlet.error.exception_type 该属性给出异常的类型,异常类型可被存储,并在存储为 java.lang.Class 数据类型后可被分析 Object exceptionType = request.getAttribute("javax.servlet.error.exception_type"); // javax.servlet.error.exception 该属性给出异常的相关信息,信息可被存储,并在存储为 java.lang.Throwable 数据类型后可被分析 Throwable exception = (Throwable) request.getAttribute("javax.servlet.error.exception"); // 设置返回响应内容类型及编码 response.setContentType("text/html;charset=UTF-8"); // 以下项是抛出异常或报 404 等错误码时均有返回信息 response.getWriter().append("<br/> 访问报错 Servlet 页面返回的错误码 : " + statusCode + " 这里显示内容为 404 或 500 "); response.getWriter().append("<br/> 访问报错 Servlet 页面的请求地址 : " + requestUri + " 这里显示内容为 /HelloWorld/TomcatTest/TestServlet "); response.getWriter().append("<br/> 访问报错 Servlet 页面返回的错误信息 : " + message + " 404 错误时这里显示内容为 test response status 异常错误时显示内容为 这是测试异常信息"); response.getWriter().append("<br/> 访问报错 Servlet 页面返回的报错的 Servlet 类名 : " + servletName + " 这里显示内容为 TestServlet "); // 以下项是只有抛出异常才有值,报 404 等错误码时无返回值 response.getWriter().append("<br/> 访问报错 Servlet 页面返回的异常类型 : " + exceptionType.toString() + " 这里显示内容为 class javax.servlet.ServletException "); response.getWriter().append("<br/> 访问报错 Servlet 页面返回的异常类型 : " + exception.getClass().getName() + " 这里显示内容为 class javax.servlet.ServletException "); response.getWriter().append("<br/> 访问报错 Servlet 页面返回的异常信息 : " + exception.getMessage() + " 这里显示内容为 这是测试异常信息 "); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException doGet(request, response);
web.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- 文件路径 D:\ApacheServer\web_java\HelloWorld\WebContent\WEB-INF\web.xml --> <web-app version="2.5" 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_2_5.xsd"> <!-- 注册一个过滤器 --> <filter> <!-- 注册一个过滤器名称 --> <filter-name>TestFilter</filter-name> <!-- 该注册名对应的实际 Filter 类的完整的包及类名 --> <filter-class>com.test.TestFilter</filter-class> <!-- 为过滤器指定初始化参数,它的子元素 <param-name> 指定参数的名字,<param-value> 指定参数的值 --> <init-param> <param-name>testParam</param-name> <param-value>测试配置参数值</param-value> </init-param> </filter> <!-- 方便测试,再注册一个 filter --> <filter> <filter-name>TestFilter2</filter-name> <filter-class>com.test.TestFilter</filter-class> <init-param> <param-name>testParam2</param-name> <param-value>测试配置参数值2</param-value> </init-param> </filter> <!-- web.xml 中的 filter-mapping 元素的顺序决定了某个请求时 Web 容器调用 filter 的顺序 --> <!-- <filter-mapping> 元素用于设置一个 Filter 所负责拦截的资源。一个 Filter 拦截的资源可通过两种方式来指定:资源访问的请求路径和 Servlet 名称 --> <filter-mapping> <!-- 设置负责此次过滤功能的 Filter 的注册名称即该值必须是在<filter>元素中声明过的过滤器的名字 --> <filter-name>TestFilter</filter-name> <!-- 设置该 Filter 所拦截的请求路径。此处的 /* 表示该过滤器适用于所有的 Servlet和请求路径 --> <url-pattern>/*</url-pattern> <!-- 也可以指定特定的 Servlet 注册名,在访问指定 Servlet 上应用该过滤器 --> <servlet-name>TestServlet</servlet-name> <!-- dispatcher 访问指定资源时,调用该过滤器的条件,可以是 REQUEST,,INCLUDE,,FORWARD 和 ERROR 之一,默认 REQUEST。用户可以设置一个或多个 <dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。该参数可不写 --> <dispatcher>REQUEST</dispatcher> <!-- 当用户直接访问时,Web 容器将会调用过滤器。如果目标资源是通过 RequestDispatcher 的 include() 或 forward() 方法访问时,那么该过滤器就不会被调用 --> <dispatcher>INCLUDE</dispatcher> <!-- 如果目标资源是通过 RequestDispatcher 的 include() 方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用 --> <dispatcher>FORWARD</dispatcher> <!-- 如果目标资源是通过 RequestDispatcher 的 forward() 方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用 --> <dispatcher>ERROR</dispatcher> <!-- 如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用 --> </filter-mapping> <!-- 如果拦截的请求相同,则先执行上一个 filter-mapping 中指定的 Filter --> <filter-mapping> <filter-name>TestFilter2</filter-name> <url-pattern>/TomcatTest/TestServlet</url-pattern> </filter-mapping> <servlet> <!-- Servlet 在此 xml 里的注册名 --> <servlet-name>TestServlet</servlet-name> <!-- 该注册名对应的实际 Servlet 类的完整包名类名 --> <servlet-class>com.test.TestServlet</servlet-class> </servlet> <servlet-mapping> <!-- 指定一个 Servlet 注册名 --> <servlet-name>TestServlet</servlet-name> <!-- 外部访问的网址 --> <url-pattern>/TomcatTest/TestServlet</url-pattern> </servlet-mapping> <servlet> <servlet-name>TestErrorServlet</servlet-name> <servlet-class>com.test.TestErrorServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>TestErrorServlet</servlet-name> <url-pattern>/TomcatTest/TestErrorServlet</url-pattern> </servlet-mapping> <!-- 当请求的路径报错时指定一个 Servlet 来处理及返回相应信息,但用户请求的 url 未重定向跳转 --> <error-page> <!-- 当客户端请求 web 容器返回指定错误状态代码时(示例是404,也可是403等)调用指定的 Servlet 页面 --> <error-code>404</error-code> <location>/TomcatTest/TestErrorServlet</location> </error-page> <error-page> <!-- 当客户端请求 web 容器抛出异常时调用指定的 Servlet 页面,示例的 java.lang.Throwable 对应所有web容器抛出的异常,也可换成 javax.servlet.ServletException 或 java.io.IOException 等抛出指定异常时才调用设置的 Servlet 页面 --> <exception-type>java.lang.Throwable</exception-type > <location>/TomcatTest/TestErrorServlet</location> </error-page> <!-- 设置 session 超时时间,单位分钟,该设置将覆盖 Tomcat 默认的 30 分钟超时时间 --> <session-config> <session-timeout>15</session-timeout> </session-config> </web-app>
以上是关于Servlet的主要内容,如果未能解决你的问题,请参考以下文章