Servlet applet
一、Servlet的概念以及入门
Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则;我们需要自定义类,实现Servlet接口复写方法。
入门案例步骤
- 创建JavaEE项目
- 建一个包,定义一个类,实现Servlet中的接口
-
void destroy()
: 服务被关闭之前执行一次,用于释放资源 -
ServletConfig getServletConfig()
: 获取Servlet的配置对象 -
void init(ServletConfig config)
: 服务启动或者第一次访问时被创建,初始化 -
void service(ServletRequest req, ServletResponse res)
:处理请求 -
String getServletInfo()
: 获取Servlet的版本,作者等信息。
-
// 在service中添加一句
System.out.println("某个浏览器在访问我!");
- 根据约束配置
web.xml
:【得写在根标签里面】
<servlet>
<servlet-name>Server</servlet-name>
<servlet-class>cn.lc.server.Server</servlet-class> -- 全类名
</servlet>
<servlet-mapping>
<servlet-name>Server</servlet-name>
<url-pattern>/server</url-pattern> -- 虚拟路径
</servlet-mapping>
二、Servlet执行流程
- 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
- 查找web.xml文件,是否有对应的
<url-pattern>
标签体内容。 - 如果有,则在找到对应的
<servlet-class>
全类名 - tomcat会将字节码文件加载进内存,并且创建其对象【反射机制】
- 调用其方法--
service
三、Servlet的生命周期方法【vue中的钩子函数也是这样干的】
-
init
:Servlet被创建【单例模式】:执行init
方法,只执行一次。【初始化方法嘛!】- Servlet创建时机:
- 默认情况下,第一次被访问时Servlet被创建
- 可以手动配置执行Servlet的创建时机【在
<servlet>
标签下配置】- 第一次被访问时创建:
<load-on-startup>-1</load-on-startup>
的值为负数 - 在服务器启动时创建:
<load-on-startup>0</load-on-startup>
的值为非负数
- 第一次被访问时创建:
- Servlet的init方法,只能执行一次,Servlet在内存中只存在一个对象,Servlet是单例模式的!
- 多个用户同时访问时,可能存在线程安全问题。
- 为了防止线程安全问题,尽量不要在Servlet中定义成员变量,如果非要定义,也不要去修改值!
- Servlet创建时机:
service
:提过服务的方法,service
,每次接受到相关请求,这个方法都会被调用来处理请求-
destroy
:被销毁执行此方法,只执行一次- Servlet被销毁时执行。服务器关闭是,Servlet被销毁
- 只有服务器正常关闭时,才会执行destroy方法
- destroy方法在Servlet被销毁之前执行,一般用于释放资源。
四、Servlet3.0介绍
支持注解配置。可以不需要
web.xml
了。
使用步骤
- 创建JavaEE项目,选择Servlet3.0及以上,不用勾选创建
web.xml
- 定义一个类,实现Servlet接口
- 复写方法
- 在类的上面添加
@WebServlet
注解,进行配置【 原理是通过注解获取使用了该注解的全类名 】@WebServlet("资源路径[对应的路由]")
【通过注解名获取使用了该注解的所有类的全类名的思路】:专门写一个类加载器,递归遍历项目路径下的所有包,找到所有的.class文件,获取其文件上的注解,判断是否有对应的注解@WebServlet,如果有则将全类名存入一个列表,最后将这个列表返回即可!
估计Tomcat也是使用类似的机制玩儿的。
@WebServlet("/index")
public class Index implements Servlet {
...
服务器启动时创建
@WebServlet(value="/httpindex",loadOnStartup=1)
public class Index implements Servlet {
@Override
public void init() throws ServletException {
System.out.println("我随着服务器的启动而启动!");
}
...
@WebServlet注解【接口】,源码如下
@Target({ElementType.TYPE}) //目标可以作用在类上面
@Retention(RetentionPolicy.RUNTIME)// 注解保留在运行时
@Documented // 可以生成文档
public @interface WebServlet {
String name() default ""; //相当于<Servlet-name>,不用管,只是一个对应的关系
String[] value() default {}; // 代表urlPatterns()属性配置【注解默认赋值就是给它!】
String[] urlPatterns() default {}; // 相当于<url-pattern>
int loadOnStartup() default -1; // 相当于<load-on-startup>
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
五.Servlet的体系结构
Servlet
-父接口--
-
GenericServlet
--子抽象类【与协议无关的Servlet,设计上前瞻性的考虑】--:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可-
HttpServlet
【推荐使用,HTTP协议的Servlet】 --孙抽象类--:对http协议的一种封装,service方法封装了用户的请求判断方式【get,post方法】简化操作- 定义类继承HttpServlet;
- 复写doGet/doPost方法即可
-
HttpServlet抽象类部分源码
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
...
this.doGet(req, resp);
...
} else if (method.equals("POST")) {
this.doPost(req, resp);
}...
}
六. Servlet相关配置
urlpartten:Servlet访问路径
一个Servlet可以定义多个访问路径【不建议这样写】:
@WebServlet({"/d4","/dd4","/ddd4"})
-
路径定义规则
-
/xxx
:路径匹配 -
/xxx/xxx
:多层路径,目录结构 -
/*
:匹配所有,优先级很低【不用】 -
*.do
:扩展名匹配,【注意:这里的 ''号前面别加'/'*】
-
-
完全路径匹配,以
/
开头:/xxx/xxx/xxx
-
目录匹配,以
/
开头,以*
结尾:/aaa/*
-
扩展名匹配:不能以
/
开头,以*
开头*.action
七、总结
- 生命周期:默认第一次访问的时候创建Servlet对象,执行init方法,每次请求过来之后执行Service方法,在service方法内部根据请求方式的不同调用不同的doXXX方法,Get请求调用doGet方法,Post请求调用doPost方法,当服务器关闭或者项目被移除了就销毁Servlet对象,执行destroy方法,初始化和销毁方法都只执行一次;Servet是单例,也就是说在Servlet整个生命周期中,Servet对象有且仅有一个
- http协议默认端口:80;超文本传输协议,基于请求和响应模型,请求先有,后有响应,一次请求只会有一次响应
- 程序优化思想:在HttpServlet实现子类的注解上添加loadOnStartup=1;将初始化操作放在服务器启动的时候操作【spring框架的配置文件就是这样干的】
- 项目的虚拟路径最好和项目名相同或者不写
- get请求的请求参数在请求行的请求路径后面;get请求方式没有请求体
- 请求头:
- key:value结构的,一般一个key对应一个value,也有一个key对应多个value的情况
- user-agent:浏览器的版本信息
- referer:当前这次请求从哪里发过来------防止盗取链接,做统计工作
- GET和POST的区别(面试点)
- get方式提交的数据显示在地址栏中,准确的说是在请求行中的请求路径后面,没有请求体,而post方式提交的数据不会显示在地址栏中,提交的数据在请求体中,地址栏中也可以传递参数
- get方式url的长度有限制,而post没有限制
- post方式提交数据相对安全
- 获得请求方式:
String method = request.getMethod()
获取虚拟路径(项目名):
String contextPath = request.getContextPath();
获得URI/URL:
String uri = request.getRequestURI();
StringBuffer sb = request.getRequestURL();
获得远程ip地址:
String ip = reqeust.getRemoteAddr();
- 获取请求提交的参数
获得单个值:
String value = reqeust.getParameter(String name);
获得一组值(复选框):
String[] values = request.getParameterValues(String name);
获得所有的值封装到map集合中:
Map<String,String[]> map = request.getParameterMap();
- 提交参数乱码问题的解决
get:tomcat8及以上已自主解决
post:
request.setCharacterEncoding("UTF-8"):
注意:这句话一定要写在获取参数之前
- 作为域对象存取数据
作用的范围: 一次请求响应的范围
什么时候创建:服务器收到客户端请求时创建request对象
什么时候销毁:服务器对当前这次请求做出响应后销毁
request.setAttribute(String key,Object value);
Object value = request.getAttribute(String key);
request.removeAttribute(String key)
- 转发特点写法
- 浏览器地址栏不变
- 只能在当前项目内部跳转
- 转发是一次请求一次响应
- 转发的路径编写:不需要带虚拟路径
request.getRequestDispatcher("转发路径").forward(request,response);