1.目录结构
web项目根目录
-- WEB-INF目录
-- web.xml:web项目的核心配置文件
-- classes目录:防止字节码文件的目录 部署后web同级src目录文件放在此处
-- lib:防止依赖的jar包
2. Servlet 接口,定义了Java类被访问的规则(JavaWeb的三大组件之一)
1.生命周期
- init 创建 只执行一次,在内存中也只存在一个对象,是单例
- service 提供服务,每次访问都会被调用
- destroy 销毁 服务器正常关闭时调用,被销毁之前执行,一般用于释放资源
2.访问
web.xml *不建议使用*
<servlet>
<servlet-name>demo1</servlet-name>
<servlet-class>cn.tomcat.web.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
3.0
使用注解@WebServlet
@WebServlet("/demo2") || @WebServlet(urlPatterns = {"/demo2","/d2"})
3.体系结构
GenericServlet
抽象类:将Servlet接口中除service()的其他方法做了默认空实现
HttpServlet
抽象类:对http协议的一种封装,简化操作:继承HttpServlet复写doGet/doPost
方法
3.request和response
1.request 请求消息
// 1.获取请求方式
String method = req.getMethod();
// 2.获取虚拟目录
String contextPath = req.getContextPath();
// 3.获取servlet路径
String servletPath = req.getServletPath();
// 4.获取请求参数
String queryString = req.getQueryString();
// 5.获取请求的URI
String requestURI = req.getRequestURI();
// 6.获取请求的URL
StringBuffer requestURL = req.getRequestURL();
// 7.获取协议及版本
String protocol = req.getProtocol();
// 8.获取客户机的IP地址
String remoteAddr = req.getRemoteAddr();
// 9.获取请求头中的某个值 user-agent referer
String userAgent = req.getHeader("user-agent");
// 10.获取所有的请求头名称
Enumeration<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String value = req.getHeader(name);
System.out.println(name + " --> " + value);
}
//get tomcat 8 将get乱码问题解决了
//post中文会乱码,在获取参数之前设置request的编码(应该跟页面编码保持一致)
req.setCharacterEncoding("utf-8");
// 获取请求参数
Map<String,String[]> map = req.getParameterMap();
req.getParameter("password");
2.response 响应消息
//设置状态码
resp.setStatus();
- 1xx:接收的请求正在处理,没有接收完成,一段时间后发送1xx状态码
- 2xx:成功。代表200
- 3xx:重定向。代表302(重定向)、304(访问缓存)
- 4xx:客户端错误。代表404(请求路径没有对应资源)、405(请求方式没有对应的doXxx方法)
- 5xx:服务器端错误。代表500(服务器内部出现异常)
//设置响应头
resp.setHeader(String name,String value);
- content-type:响应体数据编码格式,编码不一致又会乱码
resp.setHeader("content-type","text/html;charset=utf-8");
OR:
resp.setContentType("text/html;charset=utf-8");
- content-disposition:以什么格式打开响应体数据。
{
in-line :默认值,在当前页面打开
attachment;filename=xxx :以附件形式打开响应体。见——>文件下载
}
a.字符输出流 —— 输出字符数据到浏览器
resp.setContentType("text/html;charset=utf-8");
//获取字符输出流 流的默认编码是ISO-8859-1,所以提前设置该流的编码,告诉浏览器该使用的编码
PrintWriter printWriter = resp.getWriter();
//输出数据
//printWriter.write("hello");
printWriter.write("<h1>hello</h1>");
b.字节输出流 —— 文件下载
//获取文件名称
String filename = req.getParameter("filename");
ServletContext servletContext = this.getServletContext();
//找到图片img文件下路径
String filepath = servletContext.getRealPath("/img/" + filename);
//字节流关联图片
FileInputStream fileInputStream = new FileInputStream(filepath);
//获取文件类型
String mimeType = servletContext.getMimeType(filename);
//设置响应头content-type
resp.setContentType(mimeType);
//设置打开方式
resp.setHeader("content-disposition","attachment;filename=" + filename);
ServletOutputStream outputStream = resp.getOutputStream();
byte[] buff = new byte[10*1024];
int len = 0;
while ((len = fileInputStream.read(buff)) != -1) {
outputStream.write(buff,0,len);
}
fileInputStream.close();
//如果下载文件名中有中文乱码,那么得兼容浏览器了:
public static String getFileName (String agent,String filename) {
try {
if (agent.contains("MSIE")) {
filename = URLEncoder.encode(filename,"utf-8");
filename = filename.replace("+"," ");
} else if (agent.toLowerCase().contains("firefox")){
BASE64Encoder base64Encoder = new BASE64Encoder();
filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
filename = URLEncoder.encode(filename,"utf-8");
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return filename;
}
4.转发和重定向
1.转发 forward
- 转发地址路径不变
- 转发只能访问当前服务器下的资源
- 转发是一次请求,可以使用request对象来共享资源
req.setAttribute("username","传递的值案例");
//请求转发
req.getRequestDispatcher("/demo5").forward(req,resp);
//then:
Object username = req.getAttribute("username");
2.重定向 redirect
- 地址路径改变
- 可以访问其他服务器的资源
- 重定向是两次请求,不能使用request对象来共享资源
//设置状态码302,设置响应头location
resp.setStatus(302);
resp.setHeader("location","/test/demo5");
可简写为:
*resp.sendRedirect("/test/demo5");*
*resp.sendRedirect("https://www.baidu.com");*
5.ServletContext
整个web应用,可以和程序的容器(服务器)来通信
作用:
- 获取MIME 类型:在互联网通信过程中定义的一种文件数据类型
格式:大类型/小类型text/html
image/jpeg
- 域对象:共享数据
ServletContext对象范围:所有用户所有请求的数据 - 获取文件的真实路径
//ServletContext context = this.getServletContext();
ServletContext context = req.getServletContext();
//全局数据,使用谨慎
// context.setAttribute("one","全局共享数据");
// context.getAttribute("one");
// context.removeAttribute("one");
//web目录下资源
String filePath = context.getRealPath("/a.txt");
File file = new File(filePath);
//WEB-INF目录下的资源
context.getRealPath("/WEB-INF/b.txt");
//src目录下的资源访问
context.getRealPath("/WEB-INF/classes/c.txt");
6. Filter 过滤器(JavaWeb的三大组件之一)
定义一个类,实现接口Filter(import javax.servlet.*;
)
- 配置拦截路径 (注解
@WebFilter
) 参考servlet- web.xml配置时<filter-mapping>配置在前面的先执行
- 注解配置时为从前到后逐字比较(依照字母和数字顺序,值小的先执行)
-
dispatcherTypes
属性
FORWARD, // 转发访问资源
INCLUDE, // 包含访问的资源
REQUEST, // 默认值。浏览器直接请求资源
ASYNC, // 异步访问资源
ERROR; // 错误跳转资源
- 路径配置方式
1.具体路径:index.jsp 只有访问index.jsp的时候才会被执行
2.拦截目录:/user/* 访问user下的所有资源时,过滤器将会被执行
3.后缀名拦截:*.jsp 访问后缀名为jsp的资源时,过滤器将会被执行
4.拦截所有资源:访问所有资源时,过滤器将会被执行 - 过滤器链为栈结构
过滤器1——>过滤器2——>资源执行——>过滤器2——>过滤器1
System.out.println("过滤器执行了");
//放行——>资源执行
filterChain.doFilter(p_req,servletResponse);
System.out.println("过滤器执行了");
7. Listener 监听器(JavaWeb的三大组件之一)
事件监听机制
示例:
@WebListener
public class ListenerDemo implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
// 一般用来加载资源
System.out.println("contextInitialized");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
// 销毁资源
System.out.println("contextDestroyed");
}
}
8. 验证码示例
int width = 100;
int height = 50;
//创建一个对象,在内存中的图片
BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//设置图片背景色
Graphics graphics = bufferedImage.getGraphics();//画笔对象
graphics.setColor(Color.white);
graphics.fillRect(0,0,width,height);
//画边框
graphics.setColor(Color.red);
graphics.drawRect(0,0,width-1,height-1);
graphics.setColor(Color.blue);
String ss = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for (int i = 0; i < 4; i++) {
char c = ss.charAt((int)(Math.floor(Math.random()*ss.length())));
//画字符
graphics.drawString(String.valueOf(c),width/4/2 + width/4*i,height/2);
}
Random random = new Random();
for (int i = 0;i < 10; i++) {
int x1 = random.nextInt(width);
int x2 = random.nextInt(width);
int y1 = random.nextInt(height);
int y2 = random.nextInt(height);
//画干扰线
graphics.drawLine(x1,x2,y1,y2);
}
//图片输出
ImageIO.write(bufferedImage,"jpg",resp.getOutputStream());
9.todo 上传示例
10.使用过滤和代理进行敏感词过滤
HttpServletRequest p_req = (HttpServletRequest)Proxy.newProxyInstance(request.getClass().getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getParameter") && args != null) {
String str = (String)method.invoke(request,args);
if (str != null && str.contains("笨蛋")) {
str = str.replace("笨蛋","***");
}
return str;
}
return method.invoke(request,args);
}
});
System.out.println("过滤器执行了");
//资源执行
filterChain.doFilter(p_req,servletResponse);