javaWeb——Servlet(一)
前言:
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
最早支持Servlet标准的是JavaSoft的Java Web Server,此后,一些其它的基于Java的Web服务器开始支持标准的Servlet。
一、什么是servlet?
- 概念:运行在服务器端的小程序
Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。
将来我们自定义一个类,实现Servlet接口,复写方法。
浏览器请求动态资源找的是java类,但这种java类依赖于服务器才能运行,并且必须要遵守一定的规则(接口)才 能运行。这里的规则就是servlet 即servlet就是一个接口。
二、快速入门
1. 创建JavaEE项目
File —>java Enterprise —> 选择合适的JavaEE版本与tomcat的版本 —> 勾选WebApplication —> Next
2. 定义一个类,实现Servlet接口
package com.zxy.web.servlet;
import javax.servlet.*;
import java.io.IOException;
public class ServletDemo1 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("Hello Servlet");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
4. 配置Servlet
在web.xml中配置:
<!--配置Servlet -->
<servlet>
<servlet-name>demo1</servlet-name>
<servlet-class>com.zxy.web.servlet.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
- 由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用元素和元素完成。
- 元素用于注册Servlet,它包含有两个主要的子元素:和,分别用于设置Servlet的注册名称和Servlet的完整类名。
- 一个元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:和,分别用于指定Servlet的注册名称和Servlet的对外访问路径.
5、执行原理
流程图说明:
- 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
- 查找web.xml文件,是否有对应的标签体内容。
- 如果有,则在找到对应的全类名
- tomcat会将字节码文件加载进内存,并且创建其对象
- 调用其方法
三、servlet中的生命周期
简介:
Servlet生命周期,即阐述Servlet从产生到毁灭的整个过程。
在Servlet产生到消亡的过程中,有三个生命周期函数,初始化方法init(),处理客户请求的方法service(),终止方法destroy()。1. 被创建:执行init方法,只执行一次
- Servlet什么时候被创建?
默认情况下,第一次被访问时,Servlet被创建
可以配置执行Servlet的创建时机。
在标签下配置
1). 第一次被访问时,创建的值为负数
2). 在服务器启动时,创建
的值为0或正整数 Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的
多个用户同时访问时,可能存在线程安全问题。
解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值2. 提供服务:执行service方法,执行多次
- 每次访问Servlet时,Service方法都会被调用一次。
3. 被销毁:执行destroy方法,只执行一次
- Servlet被销毁时执行。服务器关闭时,Servlet被销毁
只有服务器正常关闭时,才会执行destroy方法。
destroy方法在Servlet被销毁之前执行,一般用于释放资源四、servlet3.0
- 好处:
支持注解配置。可以不需要web.xml了。
- 步骤:
- 创建JavaEE项目,选择Servlet的版本3.0以上,可以不创建web.xml
- 定义一个类,实现Servlet接口
- 复写方法
- 在类上使用@WebServlet注解,进行配置
@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 "";
}
五 HttpServletRequest 与 HttpServletResponse
request是请求对象,携带请求体的所有内容
response是响应对象,返回给客户访问的所有信息
javax.servlet.http Interface HttpServletRequest 是ServletRequest的子类,
https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html
javax.servlet.http Interface HttpServletResponse 是ServletResponse的子类
https://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html
登录效验 and 返回json或xml的使用
package com.lijunyang.filter;
import com.lijunyang.util.JedisPoolUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
public class loginFilter implements Filter {
private List accessList = new ArrayList<>();
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = ((HttpServletRequest) req);
String url = request.getRequestURI();
Boolean flag = false;
for (Iterator<String> list = accessList.iterator(); list.hasNext();){
StringBuffer str = new StringBuffer(list.next());
str.append("/*");
Boolean bool = Pattern.matches(str.toString(), url);
if (bool) {
// 需要校验的
String uuid = request.getHeader("JSESSIONID");
String jSessionId = JedisPoolUtils.getJsessionId(uuid);
if (jSessionId != "") { // 具备登录状态的
flag = true;
break;
} else { // 无登录状态
flag = false;
break;
}
} else {
// 不需要效验的
flag = true;
}
}
if (flag) {
chain.doFilter(req, resp);
} else {
// resp.setStatus(400) 这个可以修改http响应状态,常用
if (true) {
resp.setContentType("application/json; charset=utf-8");
resp.setCharacterEncoding("UTF-8");
OutputStream out = resp.getOutputStream();
out.write(("{\"message\":\"无登录状态\",\"error\":\"\",\"data\":\"\",\"code\":\"10001\"}").getBytes("UTF-8"));
out.flush();
out.close();
} else {
resp.setContentType("text/xml;charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
StringBuilder builder = new StringBuilder();
builder.append("<result>")
builder.append("<message>");
builder.append("无登录状态");
builder.append("</message>");
builder.append("<error>");
builder.append("");
builder.append("</error>");
builder.append("<code>");
builder.append("10001");
builder.append("</code>");
builder.append("<data>");
builder.append("10001");
builder.append("</data>");
builder.append("</result>")
out.println(builder.toString());
out.flush();
out.close();
}
}
}
public void init(FilterConfig config) throws ServletException {
accessList.add("/fileupload/upload"); // 上传图片
accessList.add("/goodsInsertOne"); // 新建商品
accessList.add("/enum_add"); // 新建枚举
}
}
六 案例
// String path = request.getContextPath();
// String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
// System.out.println("basePath:"+basePath);
// System.out.println("getContextPath:"+request.getContextPath());
// System.out.println("getServletPath:"+request.getServletPath());
// System.out.println("getRequestURI:"+request.getRequestURI());
// System.out.println("getRealPath:"+request.getRealPath("/"));
// System.out.println("getServletContext().getRealPath:" + getServletContext().getRealPath("/")); // getServletContext 可能不存在,依赖问题
// System.out.println("getQueryString:"+request.getQueryString());
/*
basePath:http://localhost:8080/test/
getContextPath:/test
getServletPath:/test.jsp
getRequestURI: /test/test.jsp HttpServletRequest
getRequestURL: http://localhost:8080/test/test.jsp ServletRequest
getRealPath:D:\Tomcat 6.0\webapps\test\
getServletContext().getRealPath:D:\Tomcat 6.0\webapps\test\
getQueryString:p=fuck
**/
设置跨域 CORS(跨域资源共享)
package com.lijunyang.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
public class accessControlAllowOriginFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
// 将ServletResponse转换为HttpServletResponse
HttpServletResponse httpResponse = (HttpServletResponse) res;
// 如果不是80端口,需要将端口加上,如果是集群,则用Nginx的地址,同理不是80端口要加上端口
String [] allowDomain= { "http://localhost:3000" };
Set allowedOrigins= new HashSet(Arrays.asList(allowDomain));
HttpServletRequest request = ((HttpServletRequest) req);
Enumeration er = request.getHeaderNames();//获取请求头的所有name值
while(er.hasMoreElements()){
String name =(String) er.nextElement();
String value = request.getHeader(name);
// System.out.println(name+"="+value);
}
String originHeader=((HttpServletRequest) req).getHeader("Origin");
if (allowedOrigins.contains(originHeader)){
httpResponse.setHeader("Access-Control-Allow-Origin", originHeader);
// httpResponse.setContentType("application/json;charset=UTF-8");
httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
httpResponse.setHeader("Access-Control-Max-Age", "3600");
httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");
// 如果要把Cookie发到服务器,需要指定Access-Control-Allow-Credentials字段为true
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Expose-Headers", "*");
}
chain.doFilter(req, res);
}
public void init(FilterConfig config) throws ServletException {
}
}