创建项目
Servlet原理
编写Servlet
package com.yang.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author Vis.Yang * @project_name * @date 2021/8/4 14:19 */ public class MyServlet extends HttpServlet { //由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); writer.print("MyServlet is Mapping Successfully"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
映射Servlet
<?xml version="1.0" encoding="UTF-8"?> <web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" metadata-complete="true"> <!--注册Servlet--> <servlet> <servlet-name>MyServlet</servlet-name> <!--指定Servlet类--> <servlet-class>com.yang.servlet.MyServlet</servlet-class> </servlet> <!--给定访问路径--> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <!--指定访问路径--> <url-pattern>/MyServlet</url-pattern> </servlet-mapping> </web-app>
配置项目路径
测试
建立子项目的方式建立也可以,可以参考 https://blog.nowcoder.net/n/1af78e06fe594514b258307227e8ce33
映射方式
一对一
<!--注册Servlet--> <servlet> <servlet-name>MyServlet</servlet-name> <!--指定Servlet类--> <servlet-class>com.yang.servlet.MyServlet</servlet-class> </servlet> <!--给定访问路径--> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <!--指定访问路径--> <url-pattern>/MyServlet</url-pattern> </servlet-mapping>
一对多
<!--注册Servlet--> <servlet> <servlet-name>MyServlet</servlet-name> <!--指定Servlet类--> <servlet-class>com.yang.servlet.MyServlet</servlet-class> </servlet> <!--给定访问路径--> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <!--指定访问路径--> <url-pattern>/MyServlet01</url-pattern> </servlet-mapping> <!--注册Servlet--> <servlet> <servlet-name>MyServlet</servlet-name> <!--指定Servlet类--> <servlet-class>com.yang.servlet.MyServlet</servlet-class> </servlet> <!--给定访问路径--> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <!--指定访问路径--> <url-pattern>/MyServlet02</url-pattern> </servlet-mapping>
通配 *
<!--注册Servlet--> <servlet> <servlet-name>MyServlet</servlet-name> <!--指定Servlet类--> <servlet-class>com.yang.servlet.MyServlet</servlet-class> </servlet> <!--给定访问路径--> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <!--指定访问路径--> <url-pattern>/MyServlet/*</url-pattern> </servlet-mapping>
注解简化Servlet配置
利用上下文,数据共享
package com.yang.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author Vis.Yang * @project_name * @date 2021/8/4 14:19 */ public class MyServlet extends HttpServlet { //由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑都一样 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); writer.print("MyServlet is Mapping Successfully"); //获取上下文 servletContext可以保存一些数据 ServletContext servletContext = this.getServletContext(); String username="Vis.Yang"; //将一个数据保存在了servletContext中,名字为:name,值为"username" servletContext.setAttribute("name",username); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
package com.yang.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author Vis.Yang * @project_name * @date 2021/8/5 21:17 */ public class GetServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext servletContext = this.getServletContext(); String name = (String) servletContext.getAttribute("name"); PrintWriter writer = resp.getWriter(); resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); writer.print(name); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
获取初始化参数
<context-param> <param-name>paramName</param-name> <param-value>jdbc:mysql://localhost:3306/databaseName</param-value> </context-param>
package com.yang.servlet; import com.sun.org.apache.bcel.internal.generic.NEW; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author Vis.Yang * @project_name * @date 2021/8/5 22:04 */ public class GetParameter extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取初始化参数 ServletContext servletContext = this.getServletContext(); String initParameter = servletContext.getInitParameter("paramName"); resp.getWriter().print(initParameter); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
HttpServletRequest 接收请求
//获取客户机IP地址 String remoteAddr = req.getRemoteAddr(); System.out.println(remoteAddr)
package com.yang.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author Vis.Yang * @project_name * @date 2021/8/4 14:19 */ public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter writer = response.getWriter(); writer.print("MyServlet is Mapping Successfully"); //获取请求时的完整路径(从http开始,到"?"前面结束) String url = request.getRequestURL() + ""; System.out.println("获取请求时的完整路径:" + url); //获取请求时的部分路径(从项目的站点名开始,到"?"前面结束) String uri = request.getRequestURI(); System.out.println("获取请求时的部分路径:" + uri); //获取请求时的参数字符串(从"?"后面开始,到最后的字符串) String queryString = request.getQueryString(); System.out.println("获取请求时的参数字符串:" + queryString); //获取请求方式(Get/Post) String method = request.getMethod(); System.out.println("获取请求方式:"+method); //获取当前协议版本(Http/1.1) protocol /ˈproʊtəkɑːl/ String protocol = request.getProtocol(); System.out.println("获取当前协议版本:"+protocol); //获取项目站点名(项目对外访问路径) String contextPath = request.getContextPath(); System.out.println("获取项目站点名:"+contextPath); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
package com.yang.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; /** * @author Vis.Yang * @project_name * @date 2021/8/4 14:19 */ public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter writer = response.getWriter(); writer.print("MyServlet is Mapping Successfully"); /*获取请求的参数*/ //获取指定名称的参数值 String uname = request.getParameter("uname"); String pwd = request.getParameter("pwd"); System.out.println("浏览器传来的用户名:"+uname+"以及密码:"+pwd); //获取指定名称的所有参数值(用于复选框传值) String[] hobbies = request.getParameterValues("hobby"); if (hobbies!=null&&hobbies.length>0){ for (String hobby : hobbies) { System.out.println(hobby); } } } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
获取请求头
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取请求头 Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()){ String name = headerNames.nextElement(); //根据名称获取请求头的值 String value = req.getHeader(name); System.out.println(name+" : "+value); } }
结果:
host : localhost:8080 connection : keep-alive cache-control : max-age=0 sec-ch-ua : "Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92" sec-ch-ua-mobile : ?0 upgrade-insecure-requests : 1 user-agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 sec-fetch-site : none sec-fetch-mode : navigate sec-fetch-user : ?1 sec-fetch-dest : document accept-encoding : gzip, deflate, br accept-language : zh-CN,zh;q=0.9
通常这样操作,不用获取全部
获取请求体
获取请求参数通用方法
POST请求乱码问题
表单提交出错404解决办法
https://blog.nowcoder.net/n/c80472eac248433bac452b91520e9dd5
请求转发:一种在服务器内部的资源跳转方式
RequestDispatcher requestDispatcher = req.getRequestDispatcher("/s02"); requestDispatcher.forward(req, resp);
package com.yang.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author Vis.Yang * @project_name * @date 2021/8/7 11:24 */ @WebServlet("/s01") public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("MyServlet被访问了"); //转发Servlet02 req.getRequestDispatcher("/s02").forward(req, resp); //RequestDispatcher requestDispatcher = req.getRequestDispatcher("/s02"); //requestDispatcher.forward(req, resp); } }
package com.yang.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author Vis.Yang * @project_name * @date 2021/8/7 11:24 */ @WebServlet("/s02") public class Servlet02 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("Servlet02也被访问了"); } }
特点: 浏览器访问地址栏不发生变化 只能转发到当前服务器内部资源中 转发使用的是同一次请求
数据共享
package com.yang.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author Vis.Yang * @project_name MyServlet * @date 2021/8/7 11:24 */ @WebServlet("/s01") public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setAttribute("msg","MyServlet's Data"); req.getRequestDispatcher("/s02").forward(req,resp); } }
package com.yang.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author Vis.Yang * @project_name Servlet02 * @date 2021/8/7 11:24 */ @WebServlet("/s02") public class Servlet02 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Object msg = req.getAttribute("msg"); System.out.println(msg); //打印的是MyServlet中request里保存的数据 } }
HttpServletResponse 处理请求
重定向:资源跳转方式
package com.yang.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author Vis.Yang * @project_name 重定向 * @date 2021/8/7 11:24 */ @WebServlet("/s01") public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("MyServlet is visited"); //设置状态码, resp.setStatus(302); //设置响应头location resp.setHeader("location","/s02"); } }
package com.yang.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @author Vis.Yang * @project_name * @date 2021/8/7 11:24 */ @WebServlet("/s02") public class MyServlet02 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("MyServlet02 is visited too"); } }
简化重定向
//设置状态码 //resp.setStatus(302); //设置响应头location //resp.setHeader("location","/s02"); resp.sendRedirect("/s02");
特点:地址栏改变 可以访问其他站点(服务器)的资源 重定向是两次请求
路径
package com.yang.servlet; 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 java.io.FileInputStream; import java.io.IOException; /** * @author Vis.Yang * @project_name 重定向 * @date 2021/8/7 11:24 */ @WebServlet("/s01") public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.获取请参数,文件名称 String filename = req.getParameter("filename"); //2.使用字节输入流加载文件进内存 //2.1 找到文件的服务器路径 ServletContext servletContext = this.getServletContext(); String realPath = servletContext.getRealPath("/img/" + filename); //2.2 用字节流关联 FileInputStream fileInputStream = new FileInputStream(realPath); //3.设置HttpServletResponse 的响应头 //获取文件的mime类型 String mimeType = servletContext.getMimeType(filename); resp.setHeader("content-type", mimeType); resp.setHeader("content-disposition", "attachment;filename=" + filename); //4.将输入流的数据写出到输出流 ServletOutputStream outputStream = resp.getOutputStream(); byte[] buff = new byte[1024 * 8]; int len = 0; while ((len = fileInputStream.read(buff)) != -1) { outputStream.write(buff, 0, len); } fileInputStream.close(); } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Download</title> </head> <body> <a href="/s01?filename=1.jpg">点击下载图片</a> <a href="/s01?filename=1.flv">点击下载视频</a> </body> </html>
jsp
jsp代码不外露,安全
注意点:
- 表达式结尾没有分号
- 表达式可以是常量、变量、表达式或方法调用(要有返回值)
- 使用 out.print( ) 将结果输出,以字符串的形式显示在页面上
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>声明 变量 方法</title> <%! /* 声明 变量 方法 */ int count = 0; int count(int i) { i += 1; return i; } %> </head> <body> i=<%=count(count)%> <% out.print("打印到屏幕"); %> <% out.print("打印到屏幕i="+count(count)); %> </body> </html>
<body> i=<%=count(count)%> <% out.print("打印到screen"); %> <% out.print("打印到screen i="+count(count)); System.out.println("打印到Console i="+count(count)); %> </body>
<%! /* 声明 变量 方法 */ int count = 0; %> 全局变量 ------------------------------------------- <% int count = 0; >% 局部变量
<% out.print("打印到screen"); /* 页面添加换行 out.print("<br>"); */ out.print("<br>"); %>
<%-- jsp注释 浏览器不可见 <%! /* 声明 变量 方法 */ int count = 0; int count(int i) { i += 1; return i; } %> --%>
<%-- jsp注释 --%>
实际开发中,大量Java代码夹杂在静态页面里,不好维护与查看,后期将使用El表达式和Jstl标签库,减少java代码