目录
Tomcat:web服务器软件
Servlet:运行在服务器端的小程序
Servlet的执行原理
Servlet中的生命周期方法
init(创建):只执行一次
service(提供服务):执行多次
@WebServlet注解
servlet的体系结构
http:超文本传输协议
请求消息数据格式
响应消息数据格式
Request
获取请求消息
获取请求行的相关方法
获取请求头的相关方法
获取请求体数据
获取请求的通用方法
中文乱码问题
请求转发
共享数据
获取ServletContext
BeanUtils工具类,简化数据封装
Response
设置响应信息
设置响应行
设置响应头
设置响应体
重定向(redirect)
乱码问题
补充知识
响应状态码
路径写法
ServletContext对象
获取方法
其它方法
服务器:安装了服务器软件的计算机
web服务器软件:接收用户的请求,处理请求,做出响应,可以部署web项目
基本操作
部署项目的方式
<Context docBase="D:\test" path="/aaa"/>
java动态项目的目录结构
-- 项目的根目录
-- WEB-INF目录:
-- web.xml:web项目的核心配置文件
-- classes目录:放置字节码文件的目录
-- lib目录:放置依赖的jar包
Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。将来我们自定义一个类,实现Servlet接口,复写方法(遵守规则,tomcat才会运行它)
1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
2. 查找web.xml文件,是否有对应的<url-pattern>标签体内容。
3. 如果有,则在找到对应的<servlet-class>全类名
4. tomcat会将字节码文件加载进内存,并且创建其对象
5. 调用其方法
在<servlet>标签下配置创建时机
Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的
尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值
每次访问Servlet时,Service方法都会被调用一次
destroy(被销毁):只执行一次
可以不用创建web.xml,在类上使用该注解进行配置
Servlet -- 接口
|
GenericServlet -- 抽象类
|
HttpServlet -- 抽象类
urlpartten:servlet访问路径
一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"})
路径定义规则
定义了,客户端和服务器端通信时,发送数据的格式
特点
历史版本
请求行
格式:请求方式 请求url 请求协议/版本
请求方式
请求头
格式:请求头:请求头值
User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
Referer:告诉服务器,当前请求从哪里来
请求空行
就是用于分割POST请求的请求头和请求体
请求体(正文)
封装post请求消息的请求参数
示例:浏览器是egde,使用post请求发送用户名和密码
分析:
第一行为请求行,最后一行为请求体(请求的数据),剩余的全是请求头
响应行
响应头
常见的响应头
响应空行
响应体:传输的数据
字符串格式
//响应行 HTTP/1.1 200 OK //响应头 Content-Type: text/html;charset=UTF-8 Content-Length: 101 //响应空行 //响应体 <html> <head> <title>$Title$</title> </head> <body> hello , response </body> </html>
request对象和response对象的原理
request对象继承体系结构
ServletRequest -- 接口
| 继承
HttpServletRequest -- 接口
| 实现
org.apache.catalina.connector.RequestFacade (我们使用的形参 实际上是这个实现类对象)
@WebServlet("/Servlet3") public class Servlet3 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); //浏览器访问:http://localhost:8080/test/Servlet3?username=tony System.out.println(request.getMethod());//请求方式 GET System.out.println(request.getContextPath());//虚拟目录 /test System.out.println(request.getServletPath());//资源目录 /Servlet3 System.out.println(request.getQueryString());//获取get方法请求参数 username=tony System.out.println(request.getRequestURI());//uri /test/Servlet3 System.out.println(request.getRequestURL());//url http://localhost:8080/test/Servlet3 System.out.println(request.getProtocol());//协议版本 HTTP/1.1 System.out.println(request.getRemoteAddr());//客户机的ip地址 0:0:0:0:0:0:0:1 } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); System.out.println(request.getHeader("User-Agent"));//获取请求头数据 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Enumeration<String> headerNames = request.getHeaderNames();//获取所有请求头名称 Enumeration枚举类型 遍历需要使用迭代器 while (headerNames.hasMoreElements()){ System.out.println(headerNames.nextElement()); } }
步骤
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); BufferedReader reader = request.getReader(); String line; while ((line=reader.readLine())!=null){ System.out.println(line);//username=admin&password=aaa } reader.close(); }
特点
步骤
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据(在转发中 共享的数据)
相关方法
@WebServlet("/Servlet2") public class Servlet2 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); request.setAttribute("username","aaa"); request.getRequestDispatcher("/Servlet4").forward(request,response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } } @WebServlet("/Servlet4") public class Servlet4 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println(request.getAttribute("username")); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
案例:用户登录
分析
//工具类 public class jdbc { private static DataSource dataSource; static { Properties properties = new Properties(); try { properties.load(jdbc.class.getClassLoader().getResourceAsStream("druid.properties")); dataSource= DruidDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); } } public static DataSource getDataSource(){ return dataSource; } } //dao 定义登录方法 public class dao { private JdbcTemplate jdbcTemplate=new JdbcTemplate(jdbc.getDataSource());//多个操作共用一个JdbcTemplate public user login(user u){ try { String sql="select * from user2 where username=? and password=?"; user user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(user.class), u.getUsername(), u.getPassword()); return user; }catch (DataAccessException e){ e.printStackTrace(); return null;//查询失败 返回null } } } //表单数据 将发送到servlet5 @WebServlet("/Servlet5") public class Servlet5 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); user user = new user(); user.setUsername(username); user.setPassword(password); dao dao = new dao(); user user1 = dao.login(user); if(user1==null){ //登录失败 返回登录页面 request.getRequestDispatcher("login.html").forward(request,response); }else{ //将用户名放进request域中,并转发至成功页面 request.setAttribute("name",username); request.getRequestDispatcher("/Servlet6").forward(request,response); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } } //成功登录 servlet6 @WebServlet("/Servlet6") public class Servlet6 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); String name = (String) request.getAttribute("name"); response.getWriter().write(name+"登录成功"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
用于封装JavaBean的(标准的Java类)
JavaBean的要求
属性:setter和getter方法截取后的产物
成员方法
示例代码
//populate示例 Map<String, String[]> map = request.getParameterMap();//获取所有的请求数据 user user = new user(); try { BeanUtils.populate(user,map);//将数据封装进user对象内 } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } //setProperty、getProperty user user = new user(); BeanUtils.setProperty(user,"username","tom");//给user对象的username属性设置为tom System.out.println(user); System.out.println(BeanUtils.getProperty(user,"username"));//获取user对象的username的值
获取字节输出流需要设置字符集
response.getOutputStream().write("你好".getBytes("utf-8"));
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); // 重定向的步骤 // response.setStatus(302);//设置状态码为302 // response.setHeader("location","/test/Servlet2");//设置响应头 // 简化形式 response.sendRedirect("/test/Servlet2"); }
原理
特点
获取的流的默认编码是ISO-8859-1,需要设置该流的编码
response.setContentType("text/html;charset=utf-8");
案例:验证码
//绘制验证码 @WebServlet("/Servlet5") public class Servlet5 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); int width=100; int height=50; BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);//图片对象 Graphics graphics = bufferedImage.getGraphics();//获取画笔 graphics.setColor(Color.PINK);//设置颜色 graphics.fillRect(0,0,width,height);//绘制矩形 graphics.setColor(Color.BLUE); graphics.drawRect(0,0,width-1,height-1);//绘制边框 String str="QWERTYUIOPASDFGHJKLMNBVCXZ1234567890"; Random random = new Random(); for (int i = 0; i < 4; i++) { int i1 = random.nextInt(str.length());//获取随机值 char c = str.charAt(i1);//获取元素 graphics.drawString(" "+c+"",width/5*i,height/2); } //干扰线 graphics.setColor(Color.GREEN); for (int i = 0; i < 5; i++) { int x1 = random.nextInt(width); int x2 = random.nextInt(width); int y1 = random.nextInt(height); int y2 = random.nextInt(height); graphics.drawLine(x1,y1,x2,y2); } ImageIO.write(bufferedImage,"jpg",response.getOutputStream()); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
//html页面 <body> <img src="/test/Servlet5" id="img"> <br> <a id="a_id" href="#">看不清,换一张</a> <script> let img = document.getElementById("img"); let a_id = document.getElementById("a_id"); img.onclick=function () { img.src="/test/Servlet5?data"+new Date().getTime(); } a_id.onclick=function () { img.src="/test/Servlet5?data"+new Date().getTime(); } </script> </body>
获取MIME类型 String getMimeType(String filename)
域对象:共享数据
获取文件的真实路径:方法:String getRealPath(String path)
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); ServletContext servletContext = this.getServletContext(); System.out.println(servletContext.getRealPath("/c.txt"));//获取web目录下的文件路径 System.out.println(servletContext.getRealPath("/WEB-INF/b.txt"));//WEB-INF目录下的文件路径 System.out.println(servletContext.getRealPath("/WEB-INF/classes/a.txt"));//src目录下的文件路径 }
案例:文件下载
@WebServlet("/Servlet7") public class Servlet7 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8"); String filename = request.getParameter("filename");//获取文件名 ServletContext servletContext = this.getServletContext(); String realPath = servletContext.getRealPath("/WEB-INF/img/" + filename); FileInputStream fileInputStream = new FileInputStream(realPath);//读取文件 String mimeType = servletContext.getMimeType(filename);//获取文件mime类型 response.setHeader("content-type",mimeType);//设置响应头类型 服务器告诉客户端的文件类型 String agant = request.getHeader("user-agent");//解决中文名称问题,目的就是让弹窗显示中文名 filename=DownLoadUtils.getFileName(agant,filename);//DownLoadUtils是一个工具类 传入客户端的浏览器信息和文件名 response.setHeader("content-disposition","attachment;filename="+filename);//打开方式为副本 固定格式 ServletOutputStream outputStream = response.getOutputStream();//将读取到的文件信息写入到服务器内存 byte[]bytes=new byte[1024*8]; int len=0; while ((len=fileInputStream.read(bytes))!=-1){ outputStream.write(bytes,0,len); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } }
<body> <a href="/test/Servlet7?filename=2.jpg">图片1</a> <a href="/test/Servlet7?filename=九尾.jpg">图片2</a> <a href="/test/Servlet7?filename=1.avi"> 视频1</a> </body>