JavaWeb技术:Tomcat、servlet
2021/10/13 22:14:35
本文主要是介绍JavaWeb技术:Tomcat、servlet,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
目录
Tomcat:web服务器软件
Servlet:运行在服务器端的小程序
Servlet的执行原理
Servlet中的生命周期方法
init(创建):只执行一次
service(提供服务):执行多次
@WebServlet注解
servlet的体系结构
http:超文本传输协议
请求消息数据格式
响应消息数据格式
Request
获取请求消息
获取请求行的相关方法
获取请求头的相关方法
获取请求体数据
获取请求的通用方法
中文乱码问题
请求转发
共享数据
获取ServletContext
BeanUtils工具类,简化数据封装
Response
设置响应信息
设置响应行
设置响应头
设置响应体
重定向(redirect)
乱码问题
补充知识
响应状态码
路径写法
ServletContext对象
获取方法
其它方法
Tomcat:web服务器软件
服务器:安装了服务器软件的计算机
web服务器软件:接收用户的请求,处理请求,做出响应,可以部署web项目
基本操作
- 软件启动:startup.bat ,运行该文件即可
- 正常关闭:shutdown.bat,运行该文件即可
- 强制关闭:点击启动窗口的X
部署项目的方式
- 直接将项目放到webapps目录下即可
- 简化部署:将项目打成一个war包(.war文件),再将war包放置到webapps目录下 war包会自动解压缩
- 配置conf/server.xml文件(tomcat核心配置文件)
- 在<Host>标签体中配置 <Context docBase=" " path=" ">
- docBase:项目存放的路径 (文件夹的路径)
- path:虚拟路径
- 访问时,ip:端口号/虚拟路径/项目内的文件名
-
<Context docBase="D:\test" path="/aaa"/>
- 在<Host>标签体中配置 <Context docBase=" " path=" ">
- 在conf/Catalina/localhost创建任意名称的xml文件,在文件中编写 <Context docBase=" ">
- 访问时的虚拟目录就是xml的文件名
java动态项目的目录结构
-- 项目的根目录
-- WEB-INF目录:
-- web.xml:web项目的核心配置文件
-- classes目录:放置字节码文件的目录
-- lib目录:放置依赖的jar包
Servlet:运行在服务器端的小程序
Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。将来我们自定义一个类,实现Servlet接口,复写方法(遵守规则,tomcat才会运行它)
Servlet的执行原理
1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
2. 查找web.xml文件,是否有对应的<url-pattern>标签体内容。
3. 如果有,则在找到对应的<servlet-class>全类名
4. tomcat会将字节码文件加载进内存,并且创建其对象
5. 调用其方法
Servlet中的生命周期方法
init(创建):只执行一次
在<servlet>标签下配置创建时机
- <load-on-startup>的值为负数 第一次被访问时,创建(默认)
- <load-on-startup>的值为0或正整数 在服务器启动时,创建
Servlet的init方法,只执行一次,说明一个Servlet在内存中只存在一个对象,Servlet是单例的
尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值
service(提供服务):执行多次
每次访问Servlet时,Service方法都会被调用一次
destroy(被销毁):只执行一次
- 只有服务器正常关闭时,才会执行destroy方法
- 一般用于销毁资源
@WebServlet注解
可以不用创建web.xml,在类上使用该注解进行配置
servlet的体系结构
Servlet -- 接口
|
GenericServlet -- 抽象类
|
HttpServlet -- 抽象类
- GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
- HttpServlet:对http协议的一种封装,简化操作,复写doGet/doPost
- service方法会先判断传输方式(get、post),再调用其方法
urlpartten:servlet访问路径
一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"})
路径定义规则
- /xxx:路径匹配
- /xxx/xxx:多层路径,目录结构
- *.do:扩展名匹配(可以是任意的后缀名称)
http:超文本传输协议
定义了,客户端和服务器端通信时,发送数据的格式
特点
- 基于TCP/IP的高级协议
- 默认端口号:80
- 基于请求/响应模型的:一次请求对应一次响应
- 无状态的:每次请求之间相互独立,不能交互数据
历史版本
- 1.0:每一次请求响应都会建立新的连接
- 1.1:复用连接(创建连接,使用后 不会立即销毁,会判断后面的请求是否会用到此连接,如果用到则会复用)
请求消息数据格式
请求行
格式:请求方式 请求url 请求协议/版本
请求方式
- get:请求参数在请求行中,在url后
- post:请求参数在请求体中
请求头
格式:请求头:请求头值
User-Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
- 可以解决浏览器兼容性问题
Referer:告诉服务器,当前请求从哪里来
- 防盗链、统计工作(可以统计从baidu、新浪...来的用户)
请求空行
就是用于分割POST请求的请求头和请求体
请求体(正文)
封装post请求消息的请求参数
示例:浏览器是egde,使用post请求发送用户名和密码
分析:
第一行为请求行,最后一行为请求体(请求的数据),剩余的全是请求头
响应消息数据格式
响应行
- 组成:协议/版本 响应状态码 状态码描述
响应头
- 格式:头名称:值
常见的响应头
- Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式
- Content-disposition:服务器告诉客户端以什么格式打开响应体数据
- in-line:默认值,在当前页面内打开
- attachment;filename=xxx:以附件形式打开响应体。应用场景:文件下载
响应空行
响应体:传输的数据
- 例如,发出的请求是一个页面,响应体就是页面信息
字符串格式
//响应行 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
request对象和response对象的原理
- tomcat服务器会根据请求url中的资源路径,创建Servlet对象
- tomcat服务器,会创建request、response对象,request对象中封装了请求数据
- tomcat将request、response对象传递给service方法,并调用方法
- 在service方法中,可以通过request获取请求消息数据,通过response设置响应消息数据
- 服务器在给浏览器做出响应之前,会从response中取出设置的响应消息数据
request对象继承体系结构
ServletRequest -- 接口
| 继承
HttpServletRequest -- 接口
| 实现
org.apache.catalina.connector.RequestFacade (我们使用的形参 实际上是这个实现类对象)
获取请求消息
获取请求行的相关方法
- String getMethod() 获取请求方式
- String getContextPath() 获取虚拟目录
- String getServletPath() 获取Servlet路径(资源路径,不包含虚拟目录)
- String getQueryString() 获取get方式请求参数
- String getRequestURI() 获取请求URI:虚拟目录/资源路径
- StringBuffer getRequestURL() 获取请求URL:http://localhost/虚拟目录/资源路径
- String getProtocol() 获取协议及版本
- String getRemoteAddr() 获取客户机的IP地址
@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); } }
获取请求头的相关方法
- String getHeader(String name) 通过请求头的名称获取请求头的值
- Enumeration<String> getHeaderNames() 获取所有的请求头名称
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()); } }
获取请求体数据
步骤
- 获取流对象
- BufferedReader getReader():获取字符输入流,只能操作字符数据
- ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据(场景:文件上传)
- 再从流对象中拿数据
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(); }
获取请求的通用方法
- String getParameter(String name) 根据参数名称获取参数值
- String[] getParameterValues(String name) 根据参数名称获取参数值的数组
- Enumeration<String> getParameterNames():获取所有请求的参数名称
- Map<String,String[]> getParameterMap():获取所有参数的map集合
中文乱码问题
- request.setCharacterEncoding("utf-8");
请求转发
特点
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器内部资源中
- 转发是一次请求
步骤
- 通过request对象获取请求转发器对象:RequestDispatcher getRequestDispatcher(String path)
- 使用RequestDispatcher对象来进行转发:forward(ServletRequest request, ServletResponse response)
共享数据
域对象:一个有作用范围的对象,可以在范围内共享数据
request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据(在转发中 共享的数据)
相关方法
- void setAttribute(String name,Object obj):存储数据
- Object getAttitude(String name):通过键获取值
- void removeAttribute(String name):通过键移除键值对
@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); } }
获取ServletContext
- ServletContext getServletContext()
案例:用户登录
分析
//工具类 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); } }
BeanUtils工具类,简化数据封装
用于封装JavaBean的(标准的Java类)
JavaBean的要求
- 类必须被public修饰
- 必须提供空参的构造器
- 成员变量必须使用private修饰
- 提供公共setter和getter方法
属性:setter和getter方法截取后的产物
- 例如:getUsername() --> Username--> username(一般属性和成员变量相同)
成员方法
- setProperty()
- getProperty()
- populate(Object obj , Map map):将map集合的键值对信息,封装到对应的JavaBean对象中
示例代码
//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
设置响应信息
设置响应行
- 设置状态码:setStatus(int sc)
设置响应头
- setHeader(String name, String value)
设置响应体
- 获取输出流(getWriter()、getOutputStream()),使用输出流,将数据输出到客户端浏览器上
获取字节输出流需要设置字符集
response.getOutputStream().write("你好".getBytes("utf-8"));
重定向(redirect)
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"); }
原理
特点
- 地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求。不能使用request对象来共享数据
乱码问题
获取的流的默认编码是ISO-8859-1,需要设置该流的编码
response.setContentType("text/html;charset=utf-8");
补充知识
响应状态码
- 1xx:服务器就收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
- 2xx:成功。代表:200
- 3xx:重定向。代表:302(重定向),304(访问缓存)
- 4xx:客户端错误。 404(请求路径没有对应的资源) 405:请求方式没有对应的doXxx方法
- 5xx:服务器端错误。代表:500(服务器内部出现异常)
路径写法
- 给客户端浏览器使用:需要加虚拟目录(重定向)
- 建议虚拟目录动态获取:request.getContextPath()
- 给服务器使用:不需要加虚拟目录(请求转发) 在服务器内部进行请求转发
案例:验证码
//绘制验证码 @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>
ServletContext对象
获取方法
- 通过request对象获取 request.getServletContext();
- 通过HttpServlet获取 this.getServletContext();
- 两个方法获取的是同一个对象
其它方法
获取MIME类型 String getMimeType(String filename)
- MIME类型:在互联网通信过程中定义的一种文件数据类型 格式: 大类型/小类型 text/html
域对象:共享数据
- setAttribute(String name,Object value)
- getAttribute(String name)
- removeAttribute(String name)
- 范围:所有用户所有请求的数据
获取文件的真实路径:方法: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>
这篇关于JavaWeb技术:Tomcat、servlet的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求
- 2024-10-01使用 golang 将ETH账户的资产平均分散到其他账户
- 2024-10-01JWT用户校验课程:从入门到实践
- 2024-10-01Server Component课程入门指南
- 2024-09-30Dnd-Kit学习:新手快速入门指南