JavaWeb学习之Servlet基础
Posted 123早点睡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWeb学习之Servlet基础相关的知识,希望对你有一定的参考价值。
学习笔记仅供参考,如有错误,请多指出
java学习路上,与君共勉
作者:小饭
前言
原理操作来源于狂神说java的视频,所用图片来源于网络
基本上是看b站视频自己摘抄的笔记,保存到csdn是为了把笔记精华分享给大家,以及方便自己复习
1,Servlet简介
Servlet就是sun公司开发动态web的一门技术
sun在这些API中提供一个接口接口叫做:Servlet,如果开发一个Servlet程序,只需要完成两个小步骤:
-
编写一个类,实现Servlet接口
-
把开发好的java类部署到web服务器中
把实现了Servlet接口的程序叫做Servlet
2,HelloServlet
Servlet接口在Sun公司有两个默认的实现类:HttpServlet,GenericServlet
-
构建一个普通Maven项目,删掉里面的src目录,在项目中建立Module;这个空工程就是Maven的主工程
-
创建java web项目后,需要添加servlet,jsp依赖到pom.xml
//servlet依赖 <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> //jsp依赖 <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> </dependency>
-
右击项目名,创建一个Module,创建一个web-Maven项目
-
关于Maven父子工程的理解:
父项目中有
<modules> <module>servlet-1</module> </modules>
父项目中java子项目可以直接使用
son extends father
-
Maven环境优化
1.修改web.xml为最新(在tomcat的webapp中找)
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0" metadata-complete="true"> </web-app>
2.将Maven的结构搭建完整
新创建mian->java->resources
-
编写一个Servlet程序
1.编写一个普通类(在java中创建包,一般为三级目录com.fan.HelloServlet)
2.实现Servlet接口,直接继承HttpServlet
public class HttpServletDemo extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
System.out.println("进入到doGet方法");
resp.setContentType("text/html;charset=UTF-8");//防止中文乱码
PrintWriter writer = resp.getWriter();
writer.println("HelloServlet,好好学习");
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
doGet(req, resp);
编写Servlet的映射
为什么需要映射:我们写的是java程序,但是程序需要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务器中注册我们写的Servlet,还需要给她一个浏览器可以访问的路径;
<!--注册servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.fan.Servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern> <!--映射-->
</servlet-mapping>
配置tomcat
注意:配置项目发布的路径
启动测试
提示:如果项目出现中文乱码问题
在java文件中写入: resp.setContentType("text/html;charset=UTF-8");
3,Servlet原理
1, Servlet原理图:
2, Mapping问题
-
一个Servlet可以指定一个映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
-
一个Servlet可以指定多个映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello2</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/hello3</url-pattern> </servlet-mapping>
-
一个Servlet可以指定通用映射路径
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
/*:通配符,代表输入任何东西
-
一个Servlet可以指定一些后缀或者前缀等等
-
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> //默认请求路径(不建议这种写法)
-
<servlet-mapping> <servlet-name>hello</servlet-name> <url-pattern>*.fan</url-pattern> </servlet-mapping> //可以自定义后缀实现映射,但是注意*前面不能加项目映射路径
-
优先级问题
制定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求。
4,ServletContext
web容器在启动的时候,它会为每个web程序创建一个ServletContext对象。它代表了当前的web应用
共享数据:
我在这个servlet中保存的数据,可以在另外一个servlet中拿到
写两个java文件
set:
public class HelloServletDemo extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
System.out.println("hello word");
ServletContext context = this.getServletContext();
String username = "小饭";
context.setAttribute("username",username);//将一个数据保存在ServletContext中,名字为:username,值为:username
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
doGet(req, resp);
get:
public class GetServlet extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
ServletContext context = this.getServletContext();
String username = (String) context.getAttribute("username");//强转
resp.setContentType("text/html;charset=UTF-8");//防止中文乱码
resp.getWriter().println("名字"+username);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
配置web.xml文件 注册两个servlet
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.fan.servlet.HelloServletDemo</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getc</servlet-name>
<servlet-class>com.fan.servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getc</servlet-name>
<url-pattern>/getc</url-pattern>
</servlet-mapping>
最后:测试访问结果
如果先访问get,页面显示名字+null,
如果先访问set,再进入get,则输出名字+set输入的内容
获取初始化参数
<!--配置一些web应用的初始化参数 -->
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/study?&useSSL=false&serverTimezone=UTC</param-value>
</context-param>
public class Servlet03 extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
ServletContext context = this.getServletContext();
String url = context.getInitParameter("url");
resp.getWriter().println(url);
resp.setContentType("text/html,charset=UTF-8");
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
注册servlet(上文有教程)
请求转发
从a中向b发送指令需求c的内容,b则询问c,c把内容返回给b,a则可以在访问b中得到c的内容
public class Servlet04 extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
System.out.println("进入了demo04");
ServletContext context = this.getServletContext();
// RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");//转发的路径
// requestDispatcher.forward(req,resp);//调用forword实现请求转发;
context.getRequestDispatcher("/gp").forward(req,resp);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
注册servlet,然后访问servlet04,得出的结果是/gp路径的结果
读取资源文件
Properties
-
在java目录中新建properties
-
在resources目录下新建properties
发现都被打包到同一路径:classes,俗称这个路径为:classpath
思路:需要一个文件流:
properties类:
public class PropertiesServlet extends HttpServlet
public void test()
Properties properties = new Properties();
public class Servlet05 extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
InputStream is = this.getServletContext().getResourceAsStream("/WEB_INF/classes/db.properties");
Properties pro = new Properties();
pro.load(is);
String user = pro.getProperty("username");
String pwd = pro.getProperty("password");
resp.getWriter().println(user+":"+pwd);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
username=root
password=123456
访问测试即可
5,HttpServletResponse
web服务器接收到客户端的http请求,针对这个请求分别创建一个代表请求的HttpServletRequest对象,代表响应的一个HttpResponse
-
如果要获取客户端请求过来的参数:找HttpServletRequest
-
如果要给客户端响应一些信息:找HttpServletResponse
1,简单分类
负责向服务器发送数据的方法:
ServletOutputStream getOutputStream() throws IOException; PrintWriter getwriter() throws IOException;
负责向浏览器发送响应头的方法:
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
...
响应状态码:
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_NOT_FOUND = 404;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
...
2, 常见应用
-
向浏览器输出信息
-
下载文件
-
要获取下载文件的路径
-
下载文件的名称
-
设置让浏览器能够支持下载我们的东西
-
获取下载文件的输入流
-
创建缓冲区
-
获取OutputStream对象
-
将FileOutputStream流写入到缓冲区
-
使用OutputStream将缓冲区中的数据输出到客户端
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException // 1. 要获取下载文件的路径 String realPath = "E:\\\\ideapro\\\\javaweb-servlet\\\\response\\\\src\\\\main\\\\resources\\\\翻.jpg"; System.out.println("下载文件的路径:" + realPath); // 2. 下载的文件名是啥? String fileName = realPath.substring(realPath.lastIndexOf("\\\\") + 1); // 3. 设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西,中文文件名URLEncoder.encode编码,否则有可能乱码 resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); // 4. 获取下载文件的输入流 FileInputStream in = new FileInputStream(realPath); // 5. 创建缓冲区 int len = 0; byte[] buffer = new byte[1024];//创建一个数组,存储数据 // 6. 获取OutputStream对象 ServletOutputStream out = resp.getOutputStream(); // 7. 将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区中的数据输出到客户端! while ((len = in.read(buffer)) > 0) out.write(buffer, 0, len); in.close(); out.close();
-
注意:使用web下载文件的时候,需要在实例化FileServlet 类的doGet方法里面添加以下设置(web文件头设置)
resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
URLEncoder.encode(fileName, "UTF-8") 转码
-
验证码功能
-
前端实现
-
后端实现,需要用到java图片类,即生成一个图片
public class ImageServlet extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
//浏览器3秒刷新
resp.setHeader("refresh","3");
//如何在内存中创建一个图片
BufferedImage image = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D g = (Graphics2D) image.getGraphics();//功能类似画笔
//设置图片背景色
g.setColor(Color.WHITE);
g.fillRect(0,0,80,20);
//给图片写数据
g.setColor(Color.BLUE);
g.setFont(new Font(null,Font.BOLD,20));
g.drawString(makeNum(),0,20);
//告诉浏览器这个请求用图片方式打开
resp.setContentType("image/jpeg");
//网站是存在缓存的,不让浏览器缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
//把图片写给浏览器
boolean write = ImageIO.write(image,"jpg", resp.getOutputStream());
//生成随机数
private String makeNum()
Random random = new Random();
String num = random.nextInt(9999999) + "";
StringBuffer sb = new StringBuffer();
for (int i = 0;i<7-num.length();i++)
sb.append("0");
num = sb.toString() + num;
return num;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
-
实现重定向(重点)
(B)一个web资源收到客户端请求后,(B)他会通知客户端(A)去访问另一个web资源(C),这叫做重定向
常见场景:
-
用户登录
void sendRedirect(String var1) throws IOException;
public class RedirectServlet extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
/*
resp.setHeader("Location","/response_war/image2");
resp.setStatus(302);
*/
resp.sendRedirect("/response_war/image2");//重定向
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
面试题:请你聊聊重定向和转发的区别
相同点:
页面都会实现跳转
不同点:
请求转发的时候,url不会发生变化 307
重定向的时候,url地址栏会发生变化 302
重定向例子
public class RequestTest extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
System.out.println("进入这个请求了");
//处理请求
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username+":"+password);
//重定向一定要注意路径问题,否则出现404
resp.sendRedirect("/response_war/success.jsp");
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
doGet(req, resp);
6,HttpServletRequest
HttpServletRequest 代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest中,通过这个HttpServletRequest方法,获得客户端的所有信息
1,获取前端传递的参数并且请求转发
代码部分:
//requrst
public class LoginServlet extends HttpServlet
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobbys");
System.out.println("=====================================");
//后台接收中文乱码问题
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbys));
System.out.println("=====================================");
System.out.println(req.getContextPath());
//通过请求转发
//这里的/代表当前应用
req.getRequestDispatcher("/success.jsp").forward(req,resp);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
doGet(req, resp);
前端代码(丑,自行重新设计)
<html>
<head>
<title>登录</title>
</head>
<body>
<h1>登录</h1>
<%--这里的表单表示:以post方式提交表单,提交到我们的login请求--%>
<form action="$pageContext.request.contextPath/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobbys" value="吃饭">吃饭
<input type="checkbox" name="hobbys" value="睡觉">睡觉
<input type="checkbox" name="hobbys" value="旅游">旅游
<input type="checkbox" name="hobbys" value="打球">打球
<br>
<input type="submit">
</form>
</body>
</html>
跳转成功后的代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录成功</h1>
</body>
</html>
结果:
以上是关于JavaWeb学习之Servlet基础的主要内容,如果未能解决你的问题,请参考以下文章
(转)JavaWeb学习之Servlet----Servlet的生命周期继承结构修改Servlet模板
JavaWeb学习之Servlet----ServletConfig获取配置信息ServletContext的应用(转)