Servlet学习
一、Servlet的创建与使用
(1)IDEA创建项目
首先创建Java EE项目,勾选Web Application,说明是Web应用,会添加Servlet需要的jar包。
IDEA配置Tomcat
(2)Servlet实现
在src目录下创建存放servlet的包,然后创建一个servlet类;
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//打印内容
System.out.println("创建servlet");
}
}
主要有三个点:
- 实现Servlet规范(3种方式)
- 重写Service() 方法(ctrl + o)
- 设置请求路径(注解@WebServlet)
三种方式:
//继承HttpServlet方式创建(主要)
@WebServlet(value = {"/ser01", "/ser001"}) //可以设置多个请求路径到这个servlet
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("继承HttpServlet方式创建servlet");
}
}
//继承GenericsServlet方式创建servlet,需要实现全部方法
@WebServlet("/ser02")
public class Servlet02 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("继承GenericsServlet方式创建servlet");
}
}
//实现Servlet接口方式创建servlet
@WebServlet("/ser03")
public class Servlet03 implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("实现Servlet接口方式创建servlet");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
除了使用service()调用之外,还有重写doGet和doPost方法可以处理请求。一般都是get方法,前端是form表单提交的话可以指定post方法。get方法会把参数显示在url的?后面,post方法不会显示。
//重写doGet()方法和doPost()方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Get请求...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Post请求...");
}
(3)Servlet生命周期
@WebServlet("/ser05")
public class ServletLive extends HttpServlet {
//服务器自动调用,当有请求到达servlet时,就会调用
//可调用多次
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("调用了service方法");
}
// 初始化方法,服务器自动调用,当请求到达Servlet容器时,
// 判断该Servlet对象是否存在,不存在则创建实例并初始化
@Override
public void init() throws ServletException {
System.out.println("调用了init方法");
}
//销毁方法
//只调用一次
@Override
public void destroy() {
System.out.println("调用了destroy方法");
}
}
二、HttpServletRequest对象
在service(HttpServletRequest req, HttpServletResponse resp)方法中,有两个参数,一个是请求对象request接收浏览器传过来的请求信息;另一个是响应对象response用来存放响应信息给浏览器。
这节主要是学习请求对象的一些常用方法和使用。
(1)常用方法
@WebServlet("/req01")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/* 常用方法 */
//获取请求时的完成路径,从http开始,到?结束
String url = req.getRequestURL() + "";
//获取请求时的部分路径,从项目的站点名开始,到?结束
String uri = req.getRequestURI();
//获取请求的参数字符串,从?后面开始
String params = req.getQueryString();
//获取请求方法,get/post
String method = req.getMethod();
//获取当前的协议版本,http/1.1
String protocol = req.getProtocol();
//获取项目的站点名,对外访问路径
String webApp = req.getContextPath();
/* 获取请求参数的方法 */
//获取指定名称的参数值,返回字符串
String name = req.getParameter("name");
String psw = req.getParameter("psw");
//获取指定名称的所有参数值(复选框),返回字符串数组
String[] hobbys = req.getParameterValues("hobby");
// if (hobbys != null && hobbys.length > 0) {
// for (String hobby : hobbys) {
// System.out.println("爱好:" + hobby);
// }
// }
System.out.println(hobbys.toString());
}
}
(2)请求乱码问题
由于现在的request属于接收客户端的参数,所以有其默认的语言编码,而在解析过程中默认使用的编码为ISO-8859-1(此编码不支持中文),所以解析时会出现乱码。解决方法是1. 设置request中的编码格式,告诉服务器以何种方式来解析数据;2. 或者在接收到乱码数据以后,通过相应的编码格式还原。
Tomcat8以上版本
Get请求 不会乱码
Post请求 会乱码
解决:设置服务器解析编码的格式
request.setCharacterEncoding(“UTF-8”)
@WebServlet("/req02")
public class Servlet02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求的编码格式
req.setCharacterEncoding("UTF-8");
String uname = req.getParameter("uname");
String upwd = req.getParameter("upwd");
System.out.println(uname);
}
}
(3)请求转发
一种服务器的行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的URL地址不会改变,得到响应后,服务器再将响应发送给客户端,从始至终只有一个请求发出。
req.getRequestDispatcher(“login.jsp”).forward(req, resp);
@WebServlet("/req03")
public class Servlet03 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
System.out.println("Servlet03 name :" + name);
//请求转发给Servlet04
// req.getRequestDispatcher("req04").forward(req, resp);
//请求转发到JSP页面
// req.getRequestDispatcher("login.jsp").forward(req, resp);
//请求转发到HTML页面
// req.getRequestDispatcher("login.html").forward(req, resp);
}
}
请求转发跳转
- request.getRequestDispatcher(url).forward(request, respond);
- 可以让请求从服务器跳转到客户端(或者跳转到指定的Servlet)
- 服务端行为
特点:
- 地址栏不发生改变
- 服务端行为
- 只有一个请求
(4)request作用域
因为参数中的HttpServletRequest req是一个对象,所以可以在一个请求中传递数据,作用范围:在一次请求中有效,即服务器跳转有效。可以在请求转发的过程中使用request来传递/共享数据。
req.setAttribute( key , value );
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servlet05");
//设置域对象内容
req.setAttribute("name", "admin");
req.setAttribute("age", 18);
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
req.setAttribute("list", list);
//请求转发给Servlet06
req.getRequestDispatcher("req06").forward(req, resp);
//请求转发给JSP,并通过域对象传递数据
//req.getRequestDispatcher("index.jsp").forward(req, resp);
}
Servlet获取域对象内容:
req.getAttribute( key ); //返回Object对象,要强转
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("servlet06");
//获取域对象内容,返回Object对象,要强转
String name = (String) req.getAttribute("name");
Integer age = (Integer) req.getAttribute("age");
List<String> list = (List<String>) req.getAttribute("list");
}
三、HttpServletResponse对象
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表响应的response对象。
request对象:获取客户端数据
response对象:向客户端发送数据。
HttpServletResponse的主要功能用于服务器对客户端的请求进行响应,将Web服务器处理后的结果返回给客户端。service()方法中形参接收的是HttpServletResponse接口的实例化对象,这个对象中封装了向客户端发送数据、发送响应头、发送响应状态码的方法。
(1)响应数据
接收到客户端请求后,可以通过该对象直接进行响应,响应时需要获取输出流,有两种形式:
getWriter() 获取字符流(只能响应回字符)
getOutputStream() 获取字节流(能响应一切数据)
不能同时被使用
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取字符输出流
PrintWriter writer = resp.getWriter();
//输出数据
writer.write("hello1");
//字节输出流
// ServletOutputStream out = resp.getOutputStream();
// //输出数据
// out.write("hello2".getBytes());
}
(2)响应乱码问题
因为服务器响应的数据会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则出现乱码。
对与getWriter()方式获取的字符流,响应中文必定出乱码,默认使用ISO-8859-1格式。
对于getOutputStream()方式获取的字节流,响应中文时,由于本身就是传输的字节,所以可能出现乱码。
无论如何都应该设置好服务器和客户端使用的编码格式,以确保数据正确显示。
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置服务端的编码格式
resp.setCharacterEncoding("UTF-8");
//设置客户端的编码格式
resp.setHeader("content-type","text/html;charset=UTF-8");
//同时设置
// resp.setContentType("text/html;charset=UTF-8");
//获取字符输出流
PrintWriter writer = resp.getWriter();
//输出数据
writer.write("<h2>你好</h2>");
}
(3)重定向
重定向是一种服务器指导,客户端的行为。客户端发出第一个请求,被服务器接收处理后,服务器会进行响应,在响应的同时,服务器会给客户端一个新的地址,当客户端收到响应后,会马上自动根据服务器给的新地址发起第二个请求,服务器接收请求并作出响应,重定向完成。
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//name在cdx02用getParameter拿不到
String name = req.getParameter("name");
//重定向到cdx02
resp.sendRedirect("cdx02");
}
(4)请求转发与重定向的区别
请求转发 | 重定向 |
---|---|
req.getRequestDispatcher().forward() | resp.sendRedirect() |
一次请求,数据在request域共享 | 两次请求,不共享 |
服务器端行为 | 客户端行为 |
四、 Cookie对象
Cookie是浏览器提供的一种技术,通过服务器的程序能将一些只需保存在客户端,或者在客户端处理的数据,放在本地的计算机上。
不需要通过网络传输,因而提高网页处理的效率,并且能够减少服务器的负载。
(1)创建与发送
添加到response对象中
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建Cookie对象
Cookie cookie = new Cookie("name", "admin");
//发送Cookie对象
resp.addCookie(cookie);
}
(2)获取
在服务器端只提供了一个getCookies()方法获取客户端回传的所有cookie组成的一个数组,如果需要获取单个cookie则需要通过遍历,getName获取名称,getValue获取值。
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Cookie
Cookie[] cookies = req.getCookies();
if (cookies != null && cookies.length > 0) {
for (Cookie c : cookies) {
String name = c.getName();
String value = c.getValue();
System.out.println(name + "-" + value);
}
}
}
(3)设置到期时间
用到的时候再看把。。
五、HttpSession对象
(1)获取和方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取Session
HttpSession session = req.getSession();
//获取会话标识符 JSESSIONID唯一标识符
String id = session.getId();
System.out.println(id);
//获取Session的创建时间
System.out.println(session.getCreationTime());
//获取最后一次访问时间
System.out.println(session.getLastAccessedTime());
//判断是否是新的Session对象
System.out.println(session.isNew());
}
(2)域对象
类似request对象,可以存放数据,但是范围更大,使用重定向后,在新的servelt都能用session.getAttrubute拿到数据。
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取session域对象
HttpSession session = req.getSession();
//设置域对象
session.setAttribute("uname", "admin");
session.setAttribute("upwd", "123456");
//移除session域对象
session.removeAttribute("upwd");
//request域对象
req.setAttribute("name", "zhangshan");
//请求转发
// req.getRequestDispatcher("session.jsp").forward(req, resp);
//重定向
resp.sendRedirect("session.jsp");
}
六、ServletContext对象
每个Web应用都有且仅有一个ServletContext对象,又称Application对象,从名称中可知,该对象是与应用程序相关的。在Web容器启动的时候,会为每个Web应用程序创建一个对应的Servlet对象。
该对象有两大作用,第一、作为域对象用来共享数据,此时数据在整个应用程序中共享;第二,该对象中保存了当前应用程序相关信息。例如可以通过getServerInfo()方法获取当前服务器信息,getRealPath(String path) 获取资源的真实路径等。
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过request对象获取
ServletContext servletContext = req.getServletContext();
//通过session对象获取
ServletContext servletContext1 = req.getSession().getServletContext();
//通过ServletConfig对象获取
ServletContext servletContext2 = getServletConfig().getServletContext();
//直接获取
ServletContext servletContext3 = getServletContext();
//常用方法
用到再看把。。。。
}
七、文件上传和下载
(1)上传
文件上传涉及到前台页面的编写和后台服务器代码的编写,前台发送文件,后台接收并保存文件。
前台页面:
在做文件上传的时候,会有一个上传文件的界面,首先需要一个表单,并表单的请求方式为POST,其次我们的form表单enctype必须设置为"multipart/form-data",说明表单的类型为文件上传表单。默认情况下这个表单的类型是"application/x-www-form-urlencoded",不能用于文件上传。
<form method="post" enctype="multipart/form-data" action="uploadServlet">
姓名:<input type="text" name="uname" > <br>
文件:<input type="file" name="myfile" ><br>
<button>提交</button>
</form>
后台实现:
使用注解@MultipartConfig将一个Servlet标识为支持文件上传。Servlet将multipart/form-data的POST请求封装成Part,通过Part对上传的文件进行操作。
@WebServlet("/uploadServlet")
@MultipartConfig //文件上传,要设置该注解
public class UploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("文件上传...");
//设置请求的编码格式
req.setCharacterEncoding("UTF-8");
//获取普通表单项
String uname = req.getParameter("uname");
System.out.println(uname);
//获取Part对象,Servlet将 multipart/form-data 的POST请求封装成Part对象
Part part = req.getPart("myfile");
//通过Part对象获得上传的文件名
String fileName = part.getSubmittedFileName();
System.out.println(fileName);
//得到文件存放的路径
String filePath = req.getServletContext().getRealPath("/");
System.out.println(filePath);
//上传文件到指定目录
part.write(filePath + "/" + fileName);
}
}