参考:https://how2j.cn/k/servlet/servlet-eclipse/558.html?p=136471
Servlet 本身不能独立运行,需要部署在tomcat中
1.tomcat配置 tomcat/conf/sever.xml
// 将url的根路径映射到web目录下,同时删除tomcat\webapps下的ROOT目录,可能会有冲突
<Context path="/" docBase="D:\\workspace\\j2ee\\web" debug="0" reloadable="true" />
2.项目目录结构
web目录,用来存放html页面
web/WEB-INF 存放配置文件 web.xml和class目录
web/WEB-INF/class 存放编译后的class文件
3.web.xml 提供路径与servlet的映射关系
<web-app>
<servlet>
<servlet-name>HelloServletservlet-name>
<servlet-class>HelloServletservlet-class>
// 选填,表明该Servlet会随着Tomcat的启动而初始化,调用对应的init方法
// 取值范围1-99,数字越小优先级越高
<load-on-startup>10load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>HelloServletservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
web-app>
1.处理流程
浏览器请求到达Tomcat后,根据web.xml中的映射关系,定位到LoginServlet
发现并没有LoginServlet的实例存在,于是调用LoginServlet的public无参构造方法实例化一个LoginServlet对象
Tomcat拿到实例之后,根据请求的方式去调用对应的doPost或者doGet方法。
在执行doGet()或者doPost()之前,都会先执行service(),由service()方法判断到底该调用doGet()还是doPost()
service(), doGet(), doPost() 三种方式的参数列表都是一样的,所以有时候也会**直接重写service()**方法,在其中提供相应的服务,就不用区分到底是get还是post了。
在Servlet完成工作之后,tomcat拿到被Servlet修改过的response,根据这个response生成html 字符串,然后再通过HTTP协议回发给浏览器
浏览器再根据HTTP协议获取这个html字符串,并渲染在界面上。
2.示例
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8"); // 涉及中文时进行编码转换
String name = request.getParameter("name");
String password = request.getParameter("password");
String html = null;
if ("admin".equals(name) && "123".equals(password))
html = "成功";
else
html = "失败";
response.setContentType("text/html; charset=UTF-8");
PrintWriter pw = response.getWriter();
pw.println(html);
}
}
3.生命周期
一个Servlet的生命周期由 实例化,初始化,提供服务,销毁,被回收 几个步骤组成
构造方法 只会执行一次,所以Servlet是单实例的
public class LoginServlet extends HttpServlet {
public LoginServlet() {
System.out.println("LoginServlet 构造方法 被调用");
}
public void init(ServletConfig config) {
System.out.println("init(ServletConfig)");
}
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 略
}
public void destroy() {
System.out.println("destroy()");
}
}
4.request 常见用法
// 服务端跳转,将success.html的内容发给浏览器,浏览器中的url不变
request.getRequestDispatcher("success.html").forward(request, response);
request.getParameter(): 获取单值的参数
request.getParameterValues(): 用于获取具有多值的参数,比如注册时候提交的 "hobits",可以是多选的。
request.getParameterMap(): 用于遍历所有的参数,并返回Map类型。
request.getRequestURL(): 浏览器发出请求时的完整URL,包括协议 主机名 端口(如果有)"
request.getRequestURI(): 浏览器发出请求的资源名部分,去掉了协议和主机名"
request.getQueryString(): 请求行中的参数部分,只能显示以get方式发出的参数,post方式的看不到
request.getRemoteAddr(): 浏览器所处于的客户机的IP地址
request.getRemoteHost(): 浏览器所处于的客户机的主机名
request.getRemotePort(): 浏览器所处于的客户机使用的网络端口
request.getLocalAddr(): 服务器的IP地址
request.getLocalName(): 服务器的主机名
request.getMethod(): 得到客户机请求方式一般是GET或者POST
request.getHeader() 获取浏览器传递过来的头信息。
比如getHeader("user-agent") 可以获取浏览器的基本资料,这样就能判断是firefox、IE、chrome、或者是safari浏览器
request.getHeaderNames() 获取浏览器所有的头信息名称,根据头信息名称就能遍历出所有的头信息
5.response 常用方法
PrintWriter pw= response.getWriter(); // 获取一个PrintWriter 对象
// 可以使用println(),append(),write(),format()等等方法设置返回给浏览器的html内容。
pw.println("Hello Servlet
");
// 设置响应编码和格式
response.setContentType("text/html; charset=UTF-8");
response.sendRedirect("fail.html"); // 重定向
// 通知浏览器不要使用缓存
response.setDateHeader("Expires",0 );
response.setHeader("Cache-Control","no-cache");
response.setHeader("pragma","no-cache");
6.表单提交 带文件
public class UploadPhotoServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) {
// ServletFileUpload是用来处理上传文件的,他需要一个FileItemFactory类型的参数
// FileItemFactory是一个接口,DiskFileItemFactory是他的实现类
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
String newFileName = null; // 花括号中定义的都是局部变量,想全局访问就申明在花括号外面
try{
// 浏览器以二进制的形式提交数据,request.getParameter("heroName")就无效了
List items = upload.parseRequest(request);
Iterator iter = items.iterator();
while (iter.hasNext()){
FileItem item = (FileItem)iter.next();
String fieldName = item.getFieldName(); // 获取的是表单元素的name属性
// 判断是否为常规字段,即普通的文本信息
if(item.isFormField()){
String value = item.getString(); // 获取字段的值
value = new String(value.getBytes("ISO-8859-1"), "UTF-8");
if(fieldName.equals("heroName")){
System.out.printf("字段为:%s, 值为:%s%n", fieldName, value);
}else if(fieldName.equals("heroSex")) {
System.out.printf("字段为:%s, 值为:%s%n", fieldName, value);
}
}else{
String fileName = item.getName(); // 获取上传的文件名
System.out.printf("上传文件的字段:%s,文件名为:%s%n", fieldName, fileName);
String uploadPath = request.getServletContext().getRealPath("upload");
newFileName = System.currentTimeMillis() + ".jpg";
File file = new File(uploadPath,newFileName);
item.write(file);
}
}
response.setContentType("text/html; charset=UTF-8");
PrintWriter pw = response.getWriter();
String html = "";
pw.format(html, newFileName);
}catch (Exception e){
e.printStackTrace();
}
}
}
类似django中的中间件,所有的web请求都会先经过filter,可以在里面做一些统一性的处理,如设置编码,验证是否 登陆等
1.设置编码的过滤器
package filter;
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException,ServletException {
// 类型转换,方便调用某些方法
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// 在过滤器中统一处理编码问题
request.setCharacterEncoding("UTF-8");
// 顺便再做些统计吧,应该分开写再另一个过滤器中的
String ip = request.getRemoteAddr();
String url = request.getRequestURL().toString();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = new Date();
String date = sdf.format(d);
System.out.printf("%s %s %s",date,ip,url);
// 过滤器放行,表示继续运行下一个过滤器,或者最终访问的某个servlet,jsp,html等等
chain.doFilter(request, response);
}
@Override
public void destroy(){
};
@Override
public void init(FilterConfig var1) throws ServletException{
};
}
2.检查是否登陆
package filter;
public class AuthFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String uri = request.getRequestURI();
// 判断是否是访问的login.html和login,这两个页面不需要登陆后才能访问
if (uri.endsWith("login.html") || uri.endsWith("login")) {
chain.doFilter(request, response);
return;
}
// session中取出userName,没有的话重定向到登陆页面
// 需要在登陆后设置 request.getSession().setAttribute("userName",userName);
String userName = (String) request.getSession().getAttribute("userName");
if (null == userName) {
response.sendRedirect("login.html");
return;
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
3.web.xml
<filter>
<filter-name>filter.FirstFilterfilter-name>
<filter-class>filter.FirstFilterfilter-class>
filter>
<filter-mapping>
<filter-name>filter.FirstFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>