Java Web中使用HttpServletRequest和HttpServletResoponse来封装客户端发来的请求和返回给客户端的响应。整个流程大致如下图:
HttpServletRequest
HttpServletRequest对象代表客户端的请求,开发人员通过这个对象的方法,可以获得客户的这些信息。
获取客户机信息
通过HttpServletRequest对象可以获取客户端的信息。
方法 | 说明 |
---|---|
getRequestURL() | 返回客户端发出请求时的完整URL |
getRequestURI() | 返回请求行中的资源名部分 |
getQueryString() | 返回请求行中的参数部分(参数名+值) |
getRemoteAddr() | 返回发出请求的客户机的IP地址 |
getRemoteHost() | 返回发出请求的客户机的完整主机名 |
getRemotePort() | 返回发出请求的客户机的网络端口号 |
getLocalPort() | 返回web服务器所使用的网络端口号 |
getLocalAddr() | 返回web服务器的IP地址 |
getLocalName() | 返回web服务器的主机名 |
getPathInfo() | 返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以"/"开头 |
下面看一个例子,编写一个Servlet,获取客户机信息并展示出来。
public class HttpServletRequestDemo1 extends HttpServlet{
private static final long serialVersionUID = -5563851992272269782L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setHeader("content-type", "text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("
");
out.write("请求的URL地址: " + request.getRequestURL().toString() + "
");
out.write("请求的资源: " + request.getRequestURI() + "
");
out.write("请求的URL地址中附带的参数: " + request.getQueryString() + "
");
out.write("客户端的IP地址: " + request.getRemoteAddr() + "
");
out.write("客户端的主机名: " + request.getRemoteHost() + "
");
out.write("客户端的端口号: " + request.getRemotePort() + "
");
out.write("客户端的用户: " + request.getRemoteUser() + "
");
out.write("请求的方法: " + request.getMethod() + "
");
out.write("请求的路径信息: " + request.getPathInfo() + "
");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在web.xml中添加配置。
requestDemo1
web.HttpServletRequestDemo1
requestDemo1
/requestDemo1
运行程序,在浏览器中可以查看结果。
获取客户机请求首部
通过HttpServletRequest可以获取请求报文的首部信息,获取客户机请求首部的方法包括:
- getHeader(string name)方法:String
- getHeaders(String name)方法:Enumeration
- getHeaderNames()方法:Enumeration
同样编写一个简单的例子,创建一个Servlet。
public class HttpServletRequestDemo2 extends HttpServlet{
private static final long serialVersionUID = 2156815314653251842L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setHeader("content-type", "text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// 获取所有请求首部的字段名
Enumeration reqHeaders = request.getHeaderNames();
while(reqHeaders.hasMoreElements()) {
String headName = reqHeaders.nextElement();
String headValue = request.getHeader(headName);
out.write(headName + ":" + headValue + "
");
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
然后在web.xml中进行配置。
requestDemo2
web.HttpServletRequestDemo2
requestDemo2
/requestDemo2
运行程序,在浏览器中查看结果。
获取客户机请求参数
通过HttpServletRequest可以获取前台提交的请求参数,获取客户机请求参数的方法包括:
- getParameter(String)方法,获取请求参数。
- getParameterValues(String name)方法,用来获取数组型的参数。
- getParameterMap()方法 该方法在编写框架时经常使用
- getParameterNames()方法 该方法不经常使用,获取参数名。
下面看一个通过前台提交表单的例子。首先编写页面info.jsp。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
个人信息
然后编写后台的Servlet。
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
request.setCharacterEncoding("UTF-8");
//根据表单中标签的name读取表单提交的参数
String userid = request.getParameter("userid");
String username = request.getParameter("username");
String userpasswd = request.getParameter("userpasswd");
String sex = request.getParameter("sex");
String userjob = request.getParameter("job");
String note = request.getParameter("note");
String hiddenField = request.getParameter("hiddenField");
// 获取数组
String[] insts = request.getParameterValues("inst");
String instStr = String.join(",", insts);
//将内容写入html
String html = "" +
"填写的编号: {0} " +
" 填写的用户: {1} " +
" 填写的密码: {2} " +
" 选中的性别: {3} " +
" 选中的职业: {4} " +
" 选中的爱好: {5} " +
" 填写的备注: {6} " +
" 隐藏的内容: {7} " +
"
";
html = MessageFormat.format(html, userid, username, userpasswd, sex,
userjob, instStr, note, hiddenField);
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(html);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
同样在web.xml中进行配置。
requestDemo3
web.HttpServletRequestDemo3
requestDemo3
/requestDemo3
运行程序,首先打开表单所在的页面。
填写完表单后点击提交。
request中文参数乱码问题
在前文的代码中可以看到,我们在接收POST请求的参数的时候进行了如下设置:
response.setHeader("content-type", "text/html;charset=UTF-8");
该方式通过将服务端的编码设置为和客户端一致来解决乱码问题。
GET请求由于是直接把参数放到URL中,需要获取request对象以ISO8859-1字符编码接收到的原始数据的字节数组,然后通过字节数组以指定的编码构建字符串,解决乱码问题:
String name = request.getParameter("name");//接收数据
name =new String(name.getBytes("ISO8859-1"), "UTF-8");
请求转发
请求转发指一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理。
在Servlet中实现请求转发的方式是通过ServeltContext或者HttpServletRequest的getRequestDispatcher(String path)方法,该方法返回RequestDispatcher对象,调用这个对象的forward方法可以实现请求转发。
看一个例子,编写一个简单的登陆页面login.jsp。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
登录
编写登录的Servlet,会转发到另一个Servlet。
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 8467143275313331548L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String name = request.getParameter("username");
request.setAttribute("name", name);
request.getRequestDispatcher("/servlet2").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
编写转发到的Servlet。
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 8467143275313331548L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String name = request.getParameter("username");
request.setAttribute("name", name);
request.getRequestDispatcher("/servlet2").forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在web.xml中注册Servlet。
loginServlet
web.LoginServlet
servlet2
web.Servlet2
loginServlet
/loginServlet
servlet2
/servlet2
运行程序,在登陆界面随便输个名字,点击提交。
可以看到成功跳转。
文件上传
要实现文件上传,在客户端表单的提交方法必须是post并且设置表单的enctype="multipart/form-data",其中还要包含一个文件上传组件。
在服务器中,在Servlet3.0以后只需要添加@MultipartConfig注解即可。
@MultipartConfig注解
@MultipartConfig可以带有以下属性,均为可选的:
- maxFileSize:表示最多可以上传的文件的容量,超过设定值的文件将会遭到拒绝,默认值为-1,表示无限制。
- maxRequestSize:表示允许多部分HTTP请求的最大容量,默认值为-1,意味着它是不受限制的。
- location:将上传的文件保存在服务器中项目的指定位置,调用Part的write方法会使用,但是,只有write中填写为相对路径,那么意味着是相对于location的路径,如果是填写为绝对路径,则与location无关。
- fileSizeThreshold:设定溢出大小,超过这个值那么上传的文件就会被写入磁盘。
Part类
其中表单的每一个域都会转换为Part。可以同通过HttpServletRequest的getParts()或getPart(String name)方法获取Part。
Part类中包含如下方法:
- String getName() 获取这部分的名称,例如相关表单域的名称
- String getContentType() 如果Part是一个文件,那么将返回Part的内容类型,否则返回null(可以利用这一方法来识别是否为文件域)
- Collection
getHeaderNames() 返回这个Part中所有标头的名称 - String getHeader(String headerName) 返回指定标头名称的值
- void write(String path) 将上传的文件写入服务器中项目的指定地址下,如果path是一个绝对路径,那么将写入指定的路径,如果path是一个相对路径,那么将被写入相对于location属性值的指定路径。
- InputStream getInputStream() 以inputstream的形式返回上传文件的内容
如果HTML的输入是一个文件域,那么Part将返回这些标头:
- content-type:contentType
- content-disposition:form-data; name="filedName"; filename="fileName"
如果是一个普通文本域,那么:
- content-disposition:form-data; name="filedName"
如果是文件域,但没有上传文件,那么:
- content-type:application/octet-stream
- content-disposition:form-data; name="filedName"; filename=""
实战
下面编写一个上传图片并显示的例子。
编写上传文件的servlet。
@MultipartConfig
public class FileUploadDemo extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 创建目录
File path = new File(getServletContext().getRealPath("/upload") );
System.out.print("文件目录: " + path);
if(!path.exists()) {
path.mkdir();
}
// 获取文件
Part img = request.getPart("file1");
// 获取上传的文件名
String cd = img.getHeader("Content-Disposition");
String filename = cd.substring(cd.lastIndexOf("=")+2, cd.length()-1);
// 文件全路径
String filePath = path.getPath() + File.separator + filename;
// 写入文件
img.write(filePath);
System.out.println("File Upload: " + filePath);
// 跳转页面
request.setAttribute("filename", filename);
request.getRequestDispatcher("filedome.jsp").forward(request, response);
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
}
编写上传文件的页面index.jsp。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
登录首页
然后编写显示图片的JSP。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
展示图片内容
" />
编写配置文件web.xml。
Archetype Created Web Application
index.jsp
FileUploadServlet
com.wyk.servletdemo.web.FileUploadDemo
FileUploadServlet
/FileUploadServlet
运行程序,打开浏览器访问首页。
上传图片,点击提交,会跳转到显示图片的界面。