Servlet 是运行在服务端的Java小程序,是sun公司提供的接口规范
用来处理客户端请求,响应给浏览器的动态资源
servlet的实质就是Java代码,通过java的API动态的向客户端输出内容
编译成字节码,放到服务器上执行。
编写程序时,不需要有main函数了。当前发送一个请求的时候,服务器就会按照一定规则调用编写的代码。
第一个servlet
public class FirstServlet implements Servlet{
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("------init");
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
System.out.println("------service");
HttpServletResponse httpResponse = (HttpServletResponse)response;
httpResponse.getWriter().write("aaaaaaaaaaaaaaa");
}
@Override
public void destroy() {
System.out.println("------destroy");
}
@Override
public ServletConfig getServletConfig() {
System.out.println("------getServletConfig");
return null;
}
@Override
public String getServletInfo() {
System.out.println("------getServletInfo");
return null;
}
}
web.xml文件中配置servlet
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>com.lz.servlet.FirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myservlet</servlet-name>
<url-pattern>/first</url-pattern>
</servlet-mapping>
在浏览器中输入效果如图1:
图1
原理:在浏览器输入地址回车后。tomcat就会解析该地址,然后就会到web.xml中去匹配该地址,找到servle映射first,然后找到servlet的对应类名称,就会创建对应对象。内部机制是用反射实现的。
类的加载时机
当程序要使用某个类时,如果该类还未加载到内存中。系统会通过加载、连接
初始化三步来实现对这个类进行初始化。
- 加载
就是指将class文件读入到内存,并创建一个对象。任何类被使用时,系统都会创建对应的对象。 - 连接
验证是否有正确的内部结构,并和其他类协调一致;负责为类的静态成员分配内存,并设置默认值 - 初始化
初始化成员变量等
加载时机:创建类的实例,访问类的静态变量和赋值,调用类的静态方法,初始化某个类的子类,使用反射方式来强制创建某个类或接口对应的java.lang.Class对象。
类加载器 classLoader
负责将.class文件加载到内存中,并生成对应的Class对象。
分类:
- 根类加载器
也被称为引导类加载器,负责Java核心类的加载,比如System,String等。在jdk中jre目录下的lib目录下rt.jar文件中 - 扩展类加载器
负责jre的扩展目录中的jar包加载,在jdk中jre目录的etx目录 - 系统类加载器
负责在jvm启动时加载来自java命令的class文件以及classpath环境变量所指定的jar包和类路径。
反射
运行状态下,可以获取任意类的所有属性和方法。
对于任意对象,都能够调用它的任意一个方法和属性。
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
想要使用反射,必须的要获取字节码文件。
获取字节码文件
- 方式一 Class类中静态方法forName()
Class c1 = Class.forName("com.lz.bean.Person"); - 方式二 动态属性class
Class c2 = Person.class; - 方式三 Object类的getClass()方法
Person p = new Person();
Class c3 = p.getClass();
代码1
(获取字节码)
Class c1 = Class.forName("com.lz.reflect.Person");
通过字节码创建对象
Person p = (Person) c1.newInstance();
p.setName("phonegg");
p.setEmail("phonegg@foxmail.com");
p.show();
通过有参数的构造器来创建对象
Constructor c = c1.getConstructor(String.class, String.class);
Person p2 = (Person) c.newInstance("gjj","gjj@qq.com");
p2.show();
HttpServletRequest
@WebServlet("/request")
public class RequestServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("------------获取请求信息------------");
请求行
获取请求方式
String method = request.getMethod();
System.out.println(method);
获取请求Uri
String requestUri = request.getRequestURI(); //从项目开始
System.out.println(requestUri);
GET请求 uri /Servlet/request
POST请求 uri /Servlet/request
String requestUrl = request.getRequestURL().toString();
System.out.println(requestUrl);
GET请求 url http://localhost:8080/Servlet/request
POST请求 url http://localhost:8080/Servlet/request
请求参数
String queryString = request.getQueryString();
System.out.println(queryString);
GET请求 queryString name=aaa&age=1
GET请求 queryString null
当前项目根路径
String contextPath = request.getContextPath();
System.out.println(contextPath);
System.out.println("----------请求头信息------------");
请求头
获取所有请求头名称
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
System.out.println(" name: " + headerNames.nextElement());
}
System.out.println("----------------------");
获取指定的请求头
String header = request.getHeader("referer"); //获取访问来源
System.out.println(" referer: "+header);
// if (header.equals("http://localhost:8080/Servlet/request.html")) {
// response.sendRedirect("/Servlet/request.html");
// }
//
System.out.println("----------------------");
获取所有请求头名称和值
Enumeration<String> headerNamesValues = request.getHeaderNames();
while (headerNamesValues.hasMoreElements()) {
String name = headerNamesValues.nextElement();
String value = request.getHeader(name);
System.out.println(" name: " + name+ ", value:"+value);
}
System.out.println("---------请求体-------------");
请求体
获取请求参数
String name = request.getParameter("name");
int age = Integer.parseInt(request.getParameter("age"));
String sex = request.getParameter("sex");
System.out.println("name:"+name+", age:"+age+", sex:"+sex);
String[] hobby = request.getParameterValues("hobby");
System.out.println("爱好:"+Arrays.toString(hobby));
System.out.println("----------------------");
获取所有请求参数名称
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
System.out.println(parameterNames.nextElement());
}
System.out.println("----------------------");
获取所有请求参数键值对
Map<String, String[]> param = request.getParameterMap();
for (Map.Entry<String, String[]> entry : param.entrySet()) {
String key = entry.getKey();
String[] values = entry.getValue();
System.out.println("key="+key+", valuse="+Arrays.toString(values));
}
}
}
form表单提交中文乱码
//发送form请求时,会对请求参数进行编码,格式为ISO8859-1 不支持中文
-
单个修改 拿到单个参数修改
String sex = request.getParameter("sex");
System.out.println(sex);
byte[] bytes = sex.getBytes("ISO8859-1");
String sexUtf = new String(bytes, "utf-8");
System.out.println(sexUtf);
-
统一修改 通过request修改所有,只能用于POST请求
request.setCharacterEncoding("UTF-8");
HttpServletResponse
@WebServlet("/response")
public class ResponseServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
默认编码为 ISO 8859-1 并不支持中文
response.setCharacterEncoding("UTF-8");
告诉浏览器 使用编码格式
response.setHeader("Content-Type", "text/html;charset=UTF-8");
第一要写在最前面,否则可能仍为乱码。
response.getWriter().write("你真好");
设置响应状态码
response.setStatus(302);
添加响应头
response.addHeader("name", "lz");
response.addIntHeader("age", 20);
response.addDateHeader("my-date", new Date().getTime());
修改响应头
response.setHeader("name", "lxf");
请求重定向:
response.setHeader("location", "/Servlet/login");
response.sendRedirect("/Servlet/login");
定时重定向 各3秒后重定向
response.setHeader("refresh", "3;url=/Servlet/login");
请求转发
RequestDispatcher dispatcher = request.getRequestDispatcher("/s2");
dispatcher.forward(request, response);
}
}
重定向 和 转发 对比
-
1 写法不同
重定向: 重定向是通过response来操作的
response.setHeader("location", "/Servlet/login");
response.sendRedirect("/Servlet/login");
定时重定向 各3秒后重定向
response.setHeader("refresh", "3;url=/Servlet/login");
转发: 转发是通过request来操作
RequestDispatcher dispatcher = request.getRequestDispatcher("/s2");
dispatcher.forward(request, response); -
2 地址栏变化不同
重定向: 地址栏发生变化
转发: 地址栏不变 -
3 访问服务器次数不同
重定向: 重定向是在客户端完成操作的,浏览器访问了服务器 两次
转发: 转发是在服务器端完成操作的,浏览器访问了服务器 一次 -
4 作用范围不同
重定向: 可以重定向其他网址
转发: 只能在当前项目进行操作
ServletContext
@WebServlet("/context")
public class ContextServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
System.out.println(context);
获取WebContent下文件
String aPath = context.getRealPath("a.text");
System.out.println("a.path--"+aPath);
获取WEB-INF下文件 拼接路径
String bPath = context.getRealPath("WEB-INF/b.txt");
System.out.println("bPath----"+bPath);
获取src下的文件 先加载该文件
String cPath = this.getClass().getClassLoader().getResource("c.txt").getPath();
System.out.println(cPath);
}
}
servlet中以二进制读取图片
@WebServlet("/img")
public class ImgServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String path = getServletContext().getRealPath("noti.jpg");
输入流
FileInputStream in = new FileInputStream(path);
输出流
ServletOutputStream out = response.getOutputStream();
byte[] b = new byte[1024];
int len = 0;
while ((len = in.read(b)) != -1) {
System.out.println(len);
System.out.println(Arrays.toString(b));
out.write(b, 0, len);
}
}
}
servlet 实现下载
@WebServlet("/download")
public class DownLoadServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
提取需要下载的文件名
String filename = request.getParameter("filename");
System.out.println(filename);
//默认会对参数进行 ISO8859-1 编码, 中文名称的文件就会乱码
转回为二进制位
byte[] bname = filename.getBytes("ISO8859-1");
再使用utf-8进行编码
filename = new String(bname, "utf-8");
System.out.println(filename);
设置MIME类型, 即文件类型尾缀
String mimeType = getServletContext().getMimeType(filename);
response.setContentType(mimeType);
告诉浏览器以附件打开
response.setHeader("Content-Disposition", "attachment;");
修改下载是文件名称
response.setHeader("Content-Disposition", "attachment;filename="+filename);
根据不同浏览器进行中文编码, 因为不同浏览器默认编码不同
String agent = request.getHeader("User-Agent");
String encodedName = "";
if (agent.contains("MSIE")) {
如果是IE浏览器
encodedName = URLEncoder.encode(filename, "utf-8");
System.out.println(encodedName);
encodedName = encodedName.replace("+", " ");
System.out.println(encodedName);
} else if (agent.contains("Firefox")) {
如果是火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
encodedName = "=?utf-8?B?"+base64Encoder.encode(filename.getBytes("utf-8"))+"?=";
} else {
其他浏览器编码
encodedName = URLEncoder.encode(filename, "utf-8");
}
response.setHeader("Content-Disposition", "attachment;filename="+encodedName);
以流形式读取
String path = getServletContext().getRealPath(filename);
FileInputStream in = new FileInputStream(path);
ServletOutputStream out = response.getOutputStream();
byte[] b = new byte[1024];
int len = 0;
while ((len = in.read(b)) != -1) {
out.write(b, 0, len);
}
关闭流是否资源
in.close();
}
}
Cookie
Cookie age = new Cookie("age", "100");
//设置cookie的保存时间
age.setMaxAge(60);
//设置cookie携带路径。。。在我工程路径下都可以携带cookie
// age.setPath("/Cookie_Session");
//默认情况下,url请求头中会携带父级级路径中的cookie和同级路径的cookie
response.addCookie(age);
//删除cookie的保存时间修改为0即可。
// age.setMaxAge(0);
//获取指定cookie 比较cookie名字
Cookie[] cookies = request.getCookies();
if (cookies!=null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("age")) {
System.out.println(cookie.getValue());
}
}
}
Session
session 的创建
第一次执行request.getSession()时创建。
session 的销毁
- 服务器关闭
- session过期。默认30分钟,最后一次操作计时
- 手动销毁 session.invalidate();
- 浏览器关闭,并不一定会销毁该session,为什么访问不到session,是因为依赖JSESSIONID查找session,然而这个ID是存储在Cookie中的,在关闭浏览器后再次访问时就不会携带该ID,会重新创建session。
session 判断是否存在的依据
通过cookie中携带的JSessionId判断
HttpSession session = request.getSession();
String name = (String) session.getAttribute("name");
Integer age = (Integer) session.getAttribute("age");
session.invalidate();
System.out.println("姓名:"+name+", 年龄:"+age);
Cookie Session 对比
- cookie存储在浏览器端, session存储在服务器端。
- cookie 生命周期是从创建计时, session 的生命周期是从最后一次操作计时。
网友评论