Servlet
Servlet简介
- Servlet就是sun公司开发动态web的一门技术
- Sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成两个小步骤:
- 编写一个类,实现Servlet接口
- 把开发好的Java类部署到web服务器中。
把实现了Servlet接口的Java程序叫做,Servlet
HelloServlet
构建一个普通的Maven项目, 删掉 src,以后我们的学习,就在项目中建立Moudle
关于Maven父子工程的理解
父项目中会有:
<modules>
<module>servlet-01</module>
</modules>
子项目中会有:
<parent>
<artifactid>javaweb-02-servlet</artifactid>
<groupid>com.zhu</groupid>
<version>1.0-SNAPSHOT</version>
</parent>
Maven 环境优化
- 修改web.xml为最新
- 将maven的结构搭建完整
<!--?xml version="1.0" encoding="UTF-8"?-->
<!--Servlet 3.0 的部署描述文件 web.xml 的顶层标签 <web-app> 有一个 metadata-complete 属性,
该属性指定当前的部署描述文件是否是完全的。如果设置为 true,则容器在部署时将只依赖部署描述文件,
忽略所有的注解(同时也会跳过 web-fragment.xml 的扫描,亦即禁用可插性支持,具体请看后文关于 可插性支持的讲解);
如果不配置该属性,或者将其设置为 false,则表示启用注解支持(和可插性支持)-->
<web-app version="4.0" metadata-complete="true" 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">
</web-app>
编写一个servlet 程序
- 实现Servlet 接口 直接继承 HttpServlet
- 编写Serviet 的映射
- 为什么写映射: 我们写的是JAVA程序,但是要通过浏览器访问,浏览器需要连接web浏览器, 所以我们需要在web服务中注册我们写的Servlet 还需要给他一个浏览器能够访问的路径
导入父项目pom.xml依赖,子项目继承
<!--添加Servlet和JSP依赖-->
<dependency>
<groupid>javax.servlet</groupid>
<artifactid>javax.servlet-api</artifactid>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
父项目pom.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelversion>4.0.0</modelversion>
<groupid>com.zhu</groupid>
<artifactid>javaweb-02-servlet</artifactid>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>servlet-01</module>
</modules>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupid>javax.servlet</groupid>
<artifactid>javax.servlet-api</artifactid>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
子项目pom.xml
<!--?xml version="1.0" encoding="UTF-8"?-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelversion>4.0.0</modelversion>
<groupid>com.zhu</groupid>
<artifactid>servlet-01</artifactid>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>servlet-01 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<parent>
<artifactid>javaweb-02-servlet</artifactid>
<groupid>com.zhu</groupid>
<version>1.0-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceencoding>UTF-8</project.build.sourceencoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupid>junit</groupid>
<artifactid>junit</artifactid>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalname>servlet-01</finalname>
<pluginmanagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactid>maven-clean-plugin</artifactid>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactid>maven-resources-plugin</artifactid>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactid>maven-compiler-plugin</artifactid>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactid>maven-surefire-plugin</artifactid>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactid>maven-war-plugin</artifactid>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactid>maven-install-plugin</artifactid>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactid>maven-deploy-plugin</artifactid>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginmanagement>
</build>
</project>
编写servlet类继承HttpServlet
public class HellowServlet extends HttpServlet {
//由于gat或者post只是请求实现的不同方法,可以互相调用,业务逻辑一样
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletOutputStream outputStream = resp.getOutputStream();
PrintWriter writer = resp.getWriter();///响应流
writer.println("HellowServlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
配置web.xml映射
<!--?xml version="1.0" encoding="UTF-8"?-->
<!--Servlet 3.0 的部署描述文件 web.xml 的顶层标签 <web-app> 有一个 metadata-complete 属性,
该属性指定当前的部署描述文件是否是完全的。如果设置为 true,则容器在部署时将只依赖部署描述文件,
忽略所有的注解(同时也会跳过 web-fragment.xml 的扫描,亦即禁用可插性支持,具体请看后文关于 可插性支持的讲解);
如果不配置该属性,或者将其设置为 false,则表示启用注解支持(和可插性支持)-->
<web-app version="4.0" metadata-complete="true" 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">
<!--注册servlet-->
<servlet>
<servlet-name>hellow</servlet-name>
<servlet-class>com.kuang.servlet.HellowServlet</servlet-class>
</servlet>
<!-- servlet请求路径-->
<servlet-mapping>
<servlet-name>hellow</servlet-name>
<url-pattern>/hellow</url-pattern>
</servlet-mapping>
</web-app>
注解方式
@WebServlet("/hi")
public class HelloServlet extends HttpServlet{
}
-
配置tomcat
注意配置项目发布的路径
-
启动项目,访问路径
Servlet原理
Servlet是由Web服务器调用,web服务器在收到浏览器请求之后,会:
Mapping问题
一个Servlet可以指定一个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
一个Servlet可以指定多个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello3</url-pattern>
一个Servlet可以指定通用映射路径
- /hello/* ——> /hello后边不管写啥都返回当前带哦用的servlet-name 的方法
- /* 默认通配符
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
默认请求路径
<!--默认请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
优先级问题
<!--404-->
<servlet>
<servlet-name>error</servlet-name>
<servlet-class>com.kuang.servlet.ErrorServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
ServletContext
web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用
共享数据
public class Serlvet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//this.getServletConfig() //servlrt 配置
//this.getInitParameter() //初始化参数
//this.getServletContext(); //servlet上下文
ServletContext contxt = this.getServletContext();
String username = "JOBB"; //数据
contxt.setAttribute("username",username);//将一个数据保存在了ServletContext中, 名字为: username 值: username
System.out.println("欢迎");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
public class ReadSerlvet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//数据
ServletContext context = this.getServletContext();
String username = (String)context.getAttribute("username");
//响应
resp.setContentType("text/html");
resp.setCharacterEncoding("UTF-8");
resp.getWriter().println("姓名: "+username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
web.xml配置
<servlet>
<servlet-name>setnum</servlet-name>
<servlet-class>com.zhu.servlet.Serlvet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>setnum</servlet-name>
<url-pattern>/Serlvet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>get</servlet-name>
<servlet-class>com.zhu.servlet.ReadSerlvet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>get</servlet-name>
<url-pattern>/get</url-pattern>
</servlet-mapping>
必须先访问hello接口,然后访问get接口,才能获取name的值。
获取初始化参数
web.xml中配置
<!--Web的初始化配置-->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
java中
public class ServletContext extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
javax.servlet.ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().println(url);
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
请求转发
jpublic class ServletrequestDispatcher extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入了ServletrequestDispatcher");
ServletContext context = this.getServletContext();
//RequestDispatcher url = context.getRequestDispatcher("/url");//转发路径 格式: /url /路径
//url.forward(req,resp);//调用forward 转发
context.getRequestDispatcher("/url").forward(req,resp);//合写
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
读取资源文件
编写b.properties文件
- 在java目录下新建properties
- 在resources目录下新建properties
发现: 都被打包到了同一路径下: classes,俗称为类路径
思路: 需要一个文件流;
username = Mack
id = 00001
passworld = 123456789
public class ServletReadPropise extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
InputStream is = context.getResourceAsStream("/WEB-INF/classes/db.propise");
Properties prop = new Properties();
prop.load(is);
String username = prop.getProperty("username");
String id = prop.getProperty("id");
String passworld = prop.getProperty("passworld");
resp.getWriter().println(username+", "+passworld+", "+id);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
HttpServletResponse
web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpServletResponse;
- 如果要获取客户端请求过来的参数:找HttpServletRequest
- 如果要给客户端响应一些信息:找HttpServletResponse
简单分类
负责向浏览器发送数据的方法
ServletOutputStream getOutputStream()throwsIOException;//y
PrintWriter getWriter()throwsIOException;//一般中文用
负责向浏览器发送响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
void setDateHeader(String var1,long var2);
void addDateHeader(String var1,long var2);
void setHeader(String var1,String var2);
void addHeader(String var1,String var2);
void setIntHeader(String var1,int var2);
void addIntHeader(String var1,int var2);
响应的状态码
int SC_CONTINUE =100;int SC_SWITCHING_PROTOCOLS =101;
int SC_OK =200;int SC_CREATED =201;int SC_ACCEPTED =202;int SC_NON_AUTHORITATIVE_INFORMATION =203;int SC_NO_CONTENT =204;int SC_RESET_CONTENT =205;int SC_PARTIAL_CONTENT =206;
int SC_MULTIPLE_CHOICES =300;int SC_MOVED_PERMANENTLY =301;int SC_MOVED_TEMPORARILY =302;int SC_FOUND =302;int SC_SEE_OTHER =303;int SC_NOT_MODIFIED =304;int SC_USE_PROXY =305;int SC_TEMPORARY_REDIRECT =307;
int SC_BAD_REQUEST =400;int SC_UNAUTHORIZED =401;int SC_PAYMENT_REQUIRED =402;int SC_FORBIDDEN =403;int SC_NOT_FOUND =404;int SC_METHOD_NOT_ALLOWED =405;int SC_NOT_ACCEPTABLE =406;int SC_PROXY_AUTHENTICATION_REQUIRED =407;int SC_REQUEST_TIMEOUT =408;int SC_CONFLICT =409;int SC_GONE =410;int SC_LENGTH_REQUIRED =411;int SC_PRECONDITION_FAILED =412;int SC_REQUEST_ENTITY_TOO_LARGE =413;int SC_REQUEST_URI_TOO_LONG =414;int SC_UNSUPPORTED_MEDIA_TYPE =415;int SC_REQUESTED_RANGE_NOT_SATISFIABLE =416;int SC_EXPECTATION_FAILED =417;
int SC_INTERNAL_SERVER_ERROR =500;int SC_NOT_IMPLEMENTED =501;int SC_BAD_GATEWAY =502;int SC_SERVICE_UNAVAILABLE =503;int SC_GATEWAY_TIMEOUT =504;int SC_HTTP_VERSION_NOT_SUPPORTED =505;
/*200:请求响应成功 200
3xx:请求重定向
- 重定向:你重新到我给你新位置去;
4xx:找不到资源 404
- 资源不存在;
5xx:服务器代码错误 500 502:网关错误
*/
常见应用
下载文件
- 要获取下载文件的路径
- 下载的文件名是啥?
- 设置想办法让浏览器能够支持下载我们需要的东西
- 获取下载文件的输入流
- 创建缓冲区
- 获取OutputStream对象
- 将FileOutputStream流写入到buffer缓冲区
- 使用OutputStream将缓冲区中的数据输出到客户端!
package com.zhu;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
/**
* @author shkstart @create 2021-05-12 22:16
*/
public class Servlet_04_FileDown extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 要获取下载文件的路径
String realPath = "D:\\IDEA_project\\JavaWeb\\response\\target\\classes\\60599be88322e6675c2d7c68.jpg";
System.out.println("下载的文件的路径: "+realPath);
// 2. 下载的文件名是啥?
String filename = realPath.substring(realPath.indexOf("\\") + 1);
// 3. 设置让浏览器能够支持"Content-Disposition"下载我们需要的东西
resp.setHeader("Content-Disposition","attachment;filename= "+ URLEncoder.encode(filename,"UTF-8"));
// 4. 获取下载文件的输入流
FileInputStream in = new FileInputStream(realPath);
// 5. 创建缓冲区
int length = 0;
byte[]buffer = new byte[1024];
// 6. 获取OutputStream对象
ServletOutputStream out= resp.getOutputStream();
// 7. 将FileOutputStream流写入到buffer缓冲区
// 8. 使用OutputStream将缓冲区中的数据输出到客户端!
while ((length=in.read(buffer))>0){
out.write(buffer,0,length);
}
//关闭流
in.close();
out.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}
验证码功能
- 前端实现
- 后端实现,需要用到Java的图片类,生产一个图片
@WebServlet("/img")
public class ImageServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
//如何让浏览器3秒自动刷新一次;
resp.setHeader("refresh","3");
//在内存中创建一个图片
BufferedImage image =newBufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D g =(Graphics2D) image.getGraphics();//笔
//设置图片的背景颜色
g.setColor(Color.white);
g.fillRect(0,0,80,20);
//给图片写数据
g.setColor(Color.BLUE);
g.setFont(newFont(null,Font.BOLD,20));
g.drawString(makeNum(),0,20);
//告诉浏览器,这个请求用图片的方式打开
resp.setContentType("image/jpeg");
//网站存在缓存,不让浏览器缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
//把图片写给浏览器
ImageIO.write(image,"jpg", resp.getOutputStream());
}
//生成随机数
private String makeNum(){
Random random =newRandom();
String num = random.nextInt(9999999)+"";
StringBuffer sb =newStringBuffer();
for(int i =0; i <7-num.length(); i++){
sb.append("0");}
num = sb.toString()+ num;
return num;
}
@Override
protected void doPost(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
doGet(req, resp);
}
}
实现重定向
B一个web资源收到客户端A请求后,B会通知A去访问另外一个web资源C,这个过程叫重定向。
常见场景
用户登录
void sendRedirect(String varl)throw IOException;
测试
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
*/
resp.setHeader("Location","/r/image");
resp.setStatus(302);
resp.sendRedirect("/r/image");//重定向
}
重定向和转发的区别?
相同点: 页面都会跳转
不同点:
- 请求转发 (307)url不会产生变化, 重定向(302)会发生变化
- 请求转发 可以携带参数, 重定向不能携带参数
- 请求转发 只能发送一个请求, 重定向至少发送两次请求
简单实现登录重定向
public class Servlet_06_RequestTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入请求");
//处理请求
//从那个请求中获取参数
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username+" : "+password);
//重定向时一定要注意路径问题 否则404
resp.sendRedirect("/r/success.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<!--pom.xml引入jsp相关开始-->
<dependency>
<groupid>javax.servlet.jsp</groupid>
<artifactid>jsp-api</artifactid>
<version>2.2</version>
</dependency>
<!--引入jsp相关结束-->
<!--web.xml注册-->
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.kuang.servlet.Servlet_06_RequestTest</servlet-class>
</servlet>
<!-- servlet请求路径-->
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<!--index.xml登录页面-->
<h2>Hello World! </h2>
<%--这里提交的路径,需要寻找到项目的路径--%>
<%--${pageContext.request.contextPast}代表当前的项目--%>
<form action="${pageContext.request.contextPast}/login" method="get">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
<input type="submit">
</form>
HttpServletRequest
HttpServletRequest代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息;
获取前端传递的参数 并 请求转发
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//后台接收中文乱码问题
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbies = req.getParameterValues("hobby");
System.out.println("--------------------------------------");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbies));
System.out.println("--------------------------------------");
System.out.println(req.getContextPath());
//通过请求转发
//这里的/代表当前Web应用
req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
@WebServlet("/req")
public class ReqServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
System.out.println("url路径:"+req.getRequestURL());
System.out.println("uri路径:"+req.getRequestURI());
System.out.println("context路径:"+req.getContextPath()); req.getRequestDispatcher("/file").forward(req,resp);}
}
<!--web注册-->
<web-app version="4.0" metadata-complete="true" 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">
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>com.kuang.servlet.LoginServlet</servlet-class>
</servlet>
<!-- servlet请求路径-->
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
<!--index.xml登录页面-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<title>登录</title>
<h1>登录</h1>>
<div style="text-align: center">
<%--这里表单表示的意思:以post方式提交表单。提交到我们longin请求--%>
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text" name="password"> <br>
密码:<input type="password" name="password"> <br>
爱好:
<input type="checkbox" name="hobby" value="女孩">女孩
<input type="checkbox" name="hobby" value="唱歌">唱歌
<input type="checkbox" name="hobby" value="代码">代码
<input type="checkbox" name="hobby" value="电影">电影
<br>
<input type="submit">
</form>
</div>