1、第一个servlet应用(可以直接创建maven项目,产生maven目录结构)
导入jar包
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
创建一个类
注意: 创建的包名:不能以java开头, package com.zy.servlet; package java.com.zy.servlet(会报错的)
package com.zy.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletDemo extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("<h1>haha</h1>");
}
}
补充
如果重写的是service方法,那么所有的请求都当成get请求来执行下面的代码,如果需要判断get、post方法,通过req.getMethod()
public class ServletDemo extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("<h1>hahaha</h1>");
}
}
配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app 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"
version="4.0">
<!--配置servlet-->
<servlet>
<!--配置servlet类路径,servlet-name任意,servlet-class是一开始创建的servlet类的路径-->
<servlet-name>ServletDemo</servlet-name>
<servlet-class>com.zy.servlet.ServletDemo</servlet-class>
</servlet>
<!--servlet-name必须和上面的名字一样,url-pattern配置访问的路由 localhost:8080/my-->
<servlet-mapping>
<servlet-name>ServletDemo</servlet-name>
<url-pattern>/my</url-pattern>
</servlet-mapping>
</web-app>
启动,浏览器访问:localhost:8080/my
补充:(web3.0)可以使用注解的方式,这样就不许用配置web.xml的请求路径了
@WebServlet("/haha") //注意格式:/url ,url前必须要有"/"
public class ServletDemo implements Servlet {} //注意这个Servlet是一个接口,HttpServlet也是继承这个接口的
如果是项目部署的时候:在tomcat的webapps目录中创建一个project目录(或者直接使用ROOT目录)
将下面的文件方进去

进入tomcat的bin目录,双击startup.bat
浏览器访问 localhost:8080/project/my 也可以
总结:如果单纯是使用servlet,每一个请求都需要在xml中单独配置,非常的不方便;
仿照HttpServlet写的接口
直接继承Servlet
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ResourceBundle;
public class ServletDemo implements Servlet {
private static final ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("servlet begin");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException(lStrings.getString("http.non_http"));
}
System.out.println(request.getMethod());
response.getWriter().write(request.getMethod());
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("servlet end");
}
}
2、在来理解servlet概念
狭义的Servlet 是指Java 语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的(servlet通俗理解就是所有实现了servlet接口的实现类,程序员自己写了类继承了HTTPServlet,而HttpServlet继承了这个servlet接口,实现了这个接口,所有支持servlet标准的容器(服务器),就可以认识和处理我们写了servlet类了),一般情况下,人们将Servlet理解为后者。
Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet 只用来扩展基于HTTP协议的Web服
特点:
Servlet的运行必须要支持Servlet标准的Web容器,像Tomcat、Jboss、Weblogic、WebSphere、Jetty等都支持。
Servlet的实现遵循了服务器能够识别的规则,也就是服务器会自动的根据请求调用对应的servlet进行请求处理。
简单方便,可移植性强
运行流程:
浏览器发送请求到服务器,服务器根据请求URL地址中的URI信息在webapps目录下找到对应的项目文件夹,然后在web.xml中检索对应的servlet类(找到继承了servlet接口的类),通过反射实例化这个类。调用service方法,通过service方法来调用doget、dopost方法(注意,这个其他的方法,都是通过service方法来调用的,因为tomcat默认只会调用service方法)
3、Servlet生命周期
1、生命周期(默认)
当第一次servlet(类)被实例化加载到内存之后(默认第一次请求到来,才加载到内存),一直到服务器关闭‘
2、生命周期(配置)
在web.xml中设置了load-on-startup
<servlet>
<servlet-name>ServletDemo</servlet-name>
<servlet-class>com.zy.servlet.ServletDemo</servlet-class>
<load-on-startup>1</load-on-startup> //设置随服务器启动,就将servlet加载到内存,数字越小,越优先加载到内存中
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo</servlet-name>
<url-pattern>/my</url-pattern>
</servlet-mapping>
生命周期:当服务器启动一直到服务器关闭
4、Servlet使用
request对象也可以这样获取
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Request对象
//获取请求头数据
//获取请求方式
String method=req.getMethod();
//获取请求URL
StringBuffer url=req.getRequestURL();
String uri=req.getRequestURI();
//获取协议
String h=req.getscheme();
//获取请求行数据
//获取指定的请求行信息
String value=req.getHeader("User-Agent");
//获取所有的请求行的键的枚举
Enumeration e=req.getHeaderNames();
while(e. hasMoreElements()){
string name=(String)e. nextElement());
//获取参数
String name=req. getParameter("uname), //注意getparameter 不能获取同键不同值的多个数据(像复选框之类的);
String[] likes=req. getParameterValues("like"); //可以获取多个值了
请求的数据如果出现乱码
请求中文乱码解决:
使用公共配置
get方式:
步骤一:req.setcharacterEncoding("utf-8");
步骤二:
在tomcat的目录下的conf目录中修改server.xml文件:在Connector标签中增加属性<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" useBodyEncodingForURI="true"/> //多加了一个useBodyEncodingForURI="true";
或者参考:https://www.jb51.net/article/145741.htm
post方式:
req.setCharacterEncoding("utf-8");
请求转发学习
注意:无论项目是否有根路径(不是ROOT目录),转发的地址都是"/"
请求转发学习: 作用:实现多个servlet联动操作处理请求,这样避免代码冗余,让servlet的职责更加明确。 使用: req.getRequestDispatcher(“要转发的地址").forward(req,resp);地址:相对路径,直接书写servlet的别名即可。 特点: 一次请求,浏览器地址栏信息不改变。 注意: 请求转发后直接return结束即可。
网址栏上url不变
servlet流转过程中的数据封装
req.setAttribute("xx","xxxxx");//往req中添加数据,注意设置的是一个对象,
(String)req.getAttrubute("xx");//获取数据;注意由于之前的封装的是String对象,此时就可以强转为String对象
请求重定向
注意:如果项目有根路径(不是ROOT目录),转发的地址都是"/项目更目录/"
使用:
resp.sendRedirect("/1ogin/main");
特点
两次请求,两个request对象。
浏览器地址栏信息改变
时机:
如果请求中有表单数据,而数据又比较重要,不能重复提交,建议使用重定向。
如果请求被Servlet接收后,无法进行处理,建议使用重定向定位到可以处理的资源。
Cookie使用
Cookie学习:
作用:解决了发送的不同请求的数据共享间题
使用:
//创建Cookie对象
Cookie c=new Cookie(string name,String value);
//设置cookie(可选)
//设置有效期(默认存放在内存中,随着浏览器关闭而关闭)
c.setMaxAge(int seconds);
//设置有效路径(只有访问该路径,cookie才会附带上)
c.setPath(string uri)
//响应Cookie信息给客户端
resp.addCookie(c);
注意:
一个Cookie对象存储一条数据。多条数据,可以多创建几个Cookie对象进行存储。
特点:
浏览器端的数据存储技术。存储的数据声明在服务器端。
临时存储:存储在浏览器的运行内存中,浏览器关闭即失效。
定时存储:设置了Cookie的有效期,存储在客户端的硬盘中,在有效期内符合路径要求的请求都会附带该信息。
默认cookie信息存储好之后,每次请求都会附带,除非设置有效路径
cookie获取
//获取Cookie信息数组
Cookie[]cks=req.getcookies();
//遍历数组获取Cookie信息
使用for循环遍历即可,示例:
if(cks!=nul1){
For(Cookie c:cks){
String name=c.getName();
String value=c.getValue();
system.out.print1n(name+":"+value);
}}
Session使用
sessionid生命周期
1、浏览器第一次请求服务器时,服务器会生成一个sessionId,并返回给浏览器,这个sessionId会被保存在浏览器的会话cookie中。
2、在浏览器不关闭的情况下,之后的每次请求请求头都会携带这个sessionId到服务器(一般会设置更新服务器session时间)
3、如果浏览器一直到30分钟后,才发起第二次请求,此时的服务器session已经清空,服务器就会生成一个新的sessionId给浏览器(伴随着一个新的session存在服务器),替代之前的浏览器的sessionid
4、第三次请求,就带上的新的sessionid(cookie中保存着sessionId,如果禁用了cookie,我们可以使用url重写技术,将sessionId当作参数放到url后面)。
默认情况,session在服务器上储存为30分钟,保存了用户的一些信息,一旦session清除,用户这次登陆的所有的数据都全部清除。那我们是不是又要手动重新登陆了?我们是需要重新登陆的,只是cookie帮我们自动登录了,一般服务器会给我们浏览器上保存一个cookie,用来验证身份登陆的。每次都会默默的帮我们登陆,其实每次我们打开浏览器,打开某一个网址,这时候,cookie就会帮我们默默等登陆,只是我们感受不到而已。
所以,我们一般验证用户信息的时候(拦截器),一般先看session中是否保存了user对象,如果没有,获取cookie中的账号和密码看看是否可以登录,如果还是不行,直接跳转到登录页面;
使用:
创建session对象/获取session对象
HttpSession hs=req.getSession();如果请求中拥有session的标识符也就是JSESSIONID,则返回其对应的session对象,
如果请求中没有session的标识符也就是JSESSIONID,则创建新的session对象,并将其JSESSIONID作为从cookie数据存放到浏览器上。
如果session对象是失效了,也会重新创建一个session对象,并将其JSESSIONID存储在浏览器内存中。
设置session存储时间(单位:秒),默认30分钟,每一个请求都会重新设置失效时间
hs.setMaxInactiveInterval(5);
获取sessionid
hs.getId():
设置session强制失效
hs.invalidate();l
存储数据
hs.setAttribute("name",name);
获取数据
hs.getAttribute("name")
使用时机:
一般用户在登陆web项目时会将用户的个人信息存储到Sesion中,供该用户的其他请求使用。
直接配置session过期时间
1、在tomcat中的web.xml(conf目录下)修改这个时间
<session-config>
<session-timeout>30</session-timeout>
</session-config>
2、在项目中添加上面的代码;并设置失效的时间
ServletContext对象
需求:不同的用户需要使用同一个对象
特点:服务器创建,用户共享
生命周期:服务器启动到服务器关闭
作用域:整个项目内
getParameter()是获取POST/GET传递的参数值; getInitParameter获取Tomcat的server.xml中设置Context的初始化参数 getAttribute()是获取对象容器中的数据值; getRequestDispatcher是请求转发。
使用1
获取方式:
//第一种方式(常用)
ServletContext sc=this.getservletContext();
//第二种方式
ServletContext sc2=this.getServletConfig().getServletContext();
//第三种方式(常用)
ServletContext sc3=req.getSession().getServletContext();
//数据存储
sc.setAttribute(String name,Object value);
//数据获取
sc.getAttribute("str")返回的是0bject类型
使用2
获取项目中web.xm1文件中的全局配置数据
作用:使静态数据和代码进行解耦
1、在web.xml 配置全局数据
<!--配置全局数据-->
<context-param> //注意一个context-param只能配置一个键值对
<param-name>name</param-name>
<param-value>zhangsan</param-value>
</context-param>
2、获取
获取项目中web.xm1文件中的全局配置数据
sc.getInitParameter(String name);根据键的名字返回web.xml中配置的全局数据的值,返回String类型。如果数据不存在返回nul1。
sc.getInitParameterNames();返回键名的枚举
获取资源的绝对路径和资源的流对象
获取项目webroot下的资源的绝对路径。
String path=sc.getRealPath(String path);获取的路径为项目根目录,
path参数为项目根目录中的路径
获取webroot下的资源的流对象
InputStream is=sc.getResourceAsStream(String path);
注意:
此种方式只能获取项目根目录下的资源流对象,c1ass文件的流对象需要使用类加载器获取。
path参数为项目根目录中的路径
webroot:在tomcat服务器上,就相当于webapps的绝对路径
ServletConfig对象
作用:专门给servlet自己做配置的对象,别的servlet获取不到该数据。
操作:在web.xml配置
<servlet>
<servlet-name>ServletDemo</servlet-name>
<servlet-class>com.zy.servlet.ServletDemo</servlet-class>
<init-param> //注意只能在自己的servlet中配置数据
<param-name>name</param-name>
<param-value>zhangsan</param-value>
</init-param>
</servlet>
获取
//获取ServletConfig对象
ServletConfig sc=this.getServletConfig();
//获取web.xm1中的配置数据
String name=sc.getInitParameter("name");
System.out.print1n(name);
Response对象
//设置响应头
resp.setHeader(String name,String value);//在响应头中添加多个响应信息,但是同键会覆盖
resp.addHeader(String name,String value);//在响应头中添加多个响应信息,但是不会覆盖。
//设置响应状态码
resp. sendError(405,"this Method is not supported");
//设置响应实体(在页面上展示的)
resp.getWriter().write("this is resp study");
//设置响应编码格式,解决乱码
resp.setHeader("content-type","text/html;charset=utf-8");
resp.setContentType("text/html;charset=utf-8");//简写,text/html,会将<b></b>等html标签解析
resp.setContentType("text/plain;charset=utf-8"); //会把<b></b>等标签当做普通的文本显示在浏览器上
resp.setContentType("text/xml;charset=utf-8"); //会把响应的数据以xml的格式显示在浏览器上
web.xml解析
区别:
Web项目下的web.xml文件为局部配置,针对本项目的位置。
Tomcat下的web.xml文件为全局配置,配置公共信息。
内容(核心组件):
全局上下文配置(全局配置参数)
Servlet配置
过滤器配置
监听器配置
加载顺序:
Web容器会按ServletContext->context-param->listener->filter->servlet这个顺序加载组件,这些元素可配置在web.xml文件中的任意位置。
加载时机:
服务器启动时。
server.xml解析
核心组件
<Server>
<Service> //一个server下可以配置多个service,可以在配置端口,就可以通过不同的端口访问
<Connector/> //配置端口,可以配置多个
<Connector/>
<Engine> //引擎,只能配置一个
<Host> //配置项目的存放位置的根目录
<Context/>
</Host>
</Engine>
</Service>
</Server>
热部署
在Host中配置,如果将项目删除了,记得tomcat的server.xml要将这段代码删除掉,否则会报错,但是tomcat其他的项目还是正常的启动。
<Context path ="/Pet" reloadable ="true" docBase="F:/PetWeb"/>
解释:/Pet :虚拟路径,请求的时候需要带上
/F:/PetWeb :热部署的项目;
servlet过滤器
<filter>
<filter-name>LogFilter</filter-name>
<filter-class>com.runoob.test.LogFilter</filter-class>
<init-param>
<param-name>Site</param-name>
<param-value>菜鸟教程</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>LogFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
补充:Filter不仅可以通过url-pattern来指定拦截哪些url匹配的资源。而且还可以通过servlet-name来指定拦截哪个指定的servlet(专门为某个servlet服务了,servlet-name对应Servlet的相关配置)。
注意doFilter既可以拦截请求,可以拦截响应(是典型的责任链模式)
chain.doFilter(request,response); Systen.out.println("--MyFilter过滤器执行之后");
参考:https://www.runoob.com/jsp/jsp-writing-filters.html
https://my.oschina.net/u/1171518/blog/265467
Servlet监听器
监听器Listener就是在application,session,request三个对象创建,销毁,或者往其中添加修改删除属性时自动执行代码的功能组件。Listener是Servlet的监听器,可以监听客户端的请求,服务端的操作等。
创建几个java类实现监听接口
package com.zy.listener;
import javax.servlet.*;
import javax.servlet.http.*;
public class RequestListener implements ServletRequestListener, ServletRequestAttributeListener , HttpSessionListener , HttpSessionAttributeListener,ServletContextListener,ServletContextAttributeListener{
//对request对象
@Override
public void requestDestroyed(ServletRequestEvent sre) {
//如果某些数据有用,在销毁的前,将他存放到ServletContext中
Object xx = sre.getServletRequest().getAttribute("xx");
sre.getServletContext().setAttribute("xx",xx);
System.out.println("request对象被销毁");
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("request对象初始化");
}
//对request属性监听
@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
String name = srae.getName();
Object value = srae.getValue();
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
}
//对session对象监听
@Override
public void sessionCreated(HttpSessionEvent se) {
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
}
//对session属性的监听
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
}
//对servletcontext对象监听
@Override
public void contextInitialized(ServletContextEvent sce) {
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
//对servletcontext属性的监听
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
}
}
web.xml配置
Listener的配置信息必须在Filter和Servlet的配置之前,Listener的初始化(ServletContextListener初始化)比Servlet和Filetr都优先,而销毁比Servlet和Filter都慢。
<listener>
<listener-class>com.zy.listener.RequestListener</listener-class>
</listener>
Tomcat启动的时候,需求:加载配置文件
1、方式1:使用servlet--->init方法---><load-on-startup>
2、方式2:使用filter--->init方法--->web.xml注册过滤器之后自动调用初始化
3、方式3:使用监听器,ContextLoaderLister(spring推荐使用)
使用方式3:
需要额外导入jar包,spring-web
参考我的另一篇博客:https://i.cnblogs.com/EditPosts.aspx?postid=10827203&update=1
cookie免登陆和session综合使用
关于token:https://www.cnblogs.com/minsons/p/7058837.html
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie[] cookies = req.getCookies();
for (Cookie cookie:cookies){
if ("username".equals(cookie.getName())){
String value = cookie.getValue();
//判断用户是否存在(查数据库,验证用户是否存在)
if ("admin".equals(value)){
//设置session,存放会话
HttpSession session = req.getSession();
session.setAttribute("username",value);
resp.sendRedirect("/home");
return;
}
}
}
resp.sendRedirect("/login.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String pwd = req.getParameter("pwd");
//查询数据库,如果有用户,就设置session
if (true){
//设置cookie,免登陆
Cookie cookie = new Cookie("username",username);
cookie.setMaxAge(60*5);
cookie.setPath("/");
resp.addCookie(cookie);
//设置session,存放会话
HttpSession session = req.getSession();
session.setAttribute("username",username);
session.setAttribute("pwd",pwd);
resp.sendRedirect("/home");
}
}
}
@WebServlet("/home")
public class ServletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
Object username = session.getAttribute("username");
if(username==null){
resp.sendRedirect("/login");
return;
}
resp.setHeader("content-type","text/html;charset=utf-8");
resp.getWriter().write((String)username+"登录成功");
}
}