Hello Servlet
目录
1、什么是servlet
- Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
- 使用 Servlet,可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
- Sun公司在这些API中提供一个接口叫servlet
- 如果想开发一个servlet程序,只需要完成两个步骤:1、编写一个类,实现Servlet接口。2、把开发好的Java类部署到服务器中
- 把实现了Servlet接口的Java程序叫做,Serlet
2、HelloServlet
2.1、创建一个Maven项目
- 创键一个父Maven项目,创建web项目时都以这个父项目为基础。
- 在父maven项目pom中配置servlet依赖和jsp依赖,这样子模块共同使用方便。
-
<!--加入servlet依赖(servlet的jar)--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <!--jsp的依赖(jsp相关的jar加进来)--> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency>
- 在src\main下创建Java文件标志成蓝色源文件,与之并行创建resourcess资源文件。
- 在Java文件中创建com.***.servlet文件再创建HelloServlet类让其继承HttpServlet类,重写doGet和doPost方法。添加响应流输出(hello servlet)。
- 打开web.xml文件注册servlet和编写映射。
-
<!--注册servlet--> <servlet> <servlet-name>hello</servlet-name> <servlet-class>com.zhang.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <!-- servlet的请求路径--> <servlet-name>hello</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
配置tomcat将servlet01.war部署到服务器上端口后路劲名改为s1(为了方便)启动tomcat运行正常情况浏览器显示hello world。
问题:
出现404找不到资源,检查发现自己构造的没有在子模块党的pom文件中声明打包方式为war,导致项目打包出错,同时webapp的蓝点也没亮,在模块设置中添加web将wabapp路经写入即可,重新运行服务器就正常了。
2.2、原理
servlet是由web服务器调用,web服务器在收到浏览器请求之后,会判断servlet是否存在,若不存在则装载创建servlet的实例并初始化(若存在则跳过此步骤),然后调用service方法对请求进行处理。
3、Mapping
1.一个servlet指定多个映射路经
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello2</url-pattern>
</servlet-mapping>
2.一个servlet指定通用映射路劲
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello/*</url-pattern>
</servlet-mapping>
3.默认请求路经
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
4.指定一些后缀或者前缀。
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
一般是.do
5.优先级问题
指定了固有的映射路劲优先级最高,如果找不到路劲就走默认处理请求。
4、ServletContext
web容器在启动的时候,他会为每一个web程序都创建一个对应的ServletContext对象,它代表了当前web应用;
用处:
- 共享数据 在这个Servlet中保存的数据,可以在另外一个servlet中拿到使用
-
首先需要一个放置数据的类 System.out.println("进入doget方法"); //this.getInitParameter() 初始化参数 //this.getServletConfig() servlet配置 //this.getServletContext() servlet上下文 ServletContext servletContext = this.getServletContext(); String username = "张三";//数据 servletContext.setAttribute("username",username);//将一个数据保存在了ServletContext中 名字为:useername 值:username
然后再写一个读取数据的类 ServletContext servletContext = this.getServletContext(); String username = (String) servletContext.getAttribute("username"); resp.setContentType("text/html"); resp.setCharacterEncoding("utf-8"); resp.getWriter().println(username);
-
获取初始化参数
-
ServletContext servletContext = this.getServletContext(); String url = servletContext.getInitParameter("url"); resp.getWriter().println(url);
设置初始参数 <context-param> <param-name>url</param-name> <param-value>jdbc:mysql://localhost:3306/mybatis</param-value> </context-param>
获取请求转换
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
System.out.println("000000000000");
RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/gp");//获取请求转换路劲
requestDispatcher.forward(req,resp);//调用forward实现请求转发
}
读取资源文件
Properties
- 在Java目录下创建properties
- 在resources目录下新建properties
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
Properties properties = new Properties();
properties.load(resourceAsStream);
String username = properties.getProperty("username");
String pwd = properties.getProperty("password");
resp.getWriter().println(username+":"+pwd);
}
username = root123
password = 00000000
5、HttpServletResponse
web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求HttpServletRequest
和一个代表响应的HttpServletResponse;
- 如果要获得客户端请求过来的参数:找HttpServletRequest
- 如果要获得客户端响应的信息:找HttpServletResponse
5.1、常见应用
- 向浏览器输出信息(print)
- 下载文件
- 要获取下载的文件路径
- 下载的文件名
- 设置让浏览器能支持下载我们需要的东西
- 获取下载文件的输入流
- 创建缓冲区
- 获取OutputStresm对象
- 将FileOutputStresm流写入到buffer缓冲区
- 使用OutputStresm将缓冲区中的数据输出到客户端
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//要获取下载的文件路径
String realPath ="D:\\maven-workspace\\space02\\javaweb-04-servlet\\response\\target\\response\\WEB-INF\\classes\\这是个图片.jpg";
System.out.println("下载文件的路经:"+realPath);
//下载的文件名
String filename = realPath.substring(realPath.lastIndexOf("\\") + 1);
//设置让浏览器能支持(Content-Disposition)下载我们需要的东西
resp.setHeader("Content-Disposition","attachment;fileName="+ URLEncoder.encode(filename,"UTF-8"));
//获取下载文件的输入流
FileInputStream fileInputStream = new FileInputStream(realPath);
//创建缓冲区
int len=0;
byte[] buffer = new byte[1024];
//获取OutputStresm对象
ServletOutputStream outputStream = resp.getOutputStream();
//将FileOutputStresm流写入到buffer缓冲区
while ((len=fileInputStream.read(buffer))>0){
outputStream.write(buffer,0,len);
};
//使用OutputStresm将缓冲区中的数据输出到客户端
fileInputStream.close();
outputStream.close();
System.out.println(outputStream);
}
5.2、验证码功能
前后端都可实现验证码
后端需要用 Java 的图片类加载出一个图片
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//让浏览器3秒刷新一次
resp.setHeader("refresh","3");
//在内存中创建一个图片
BufferedImage image = new BufferedImage(40, 20, BufferedImage.TYPE_INT_RGB);
//得到图片
Graphics2D g = (Graphics2D) image.getGraphics();
g.setColor(Color.cyan);
g.fillRect(0,0,40,20);
//给图片写数据
g.setColor(Color.magenta);
g.setFont(new Font(null,Font.BOLD,20));
g.drawString(makeNum(),0,20);
//告诉浏览器,这个请求用图片的方式打开
resp.setContentType("image/jpg");
//网站存在缓存,设置浏览器不缓存
resp.setDateHeader("expires",-1);
resp.setHeader("Cache-Control","no-cache");
resp.setHeader("Pragma","no-cache");
//把图片写给浏览器
ImageIO.write(image, "jpg", resp.getOutputStream());
}
private String makeNum(){
Random random = new Random();
String s = random.nextInt(999999)+"";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 6-s.length(); i++) {
sb.append("0");
}
s=sb.toString()+s;
return s;
}
5.3、实现重定向
B一个web资源收到客户端A请求后,B会通知客户端A去访问另一个web资源C,这个过程叫做重定向。
场景:
- 登录
/*resp.setHeader("Location","/r/img");
resp.setStatus(302);
*/
resp.sendRedirect("/r/img");
5.4、重定向和转发的区别
相同点:
- 页面都会跳转
不同点:
- 请求转发的时候,URL不会发生变化 状态码:307
- 重定向时候,URL地址栏会发生变化 状态码:302
6、HttpServletRequest
HttpServletRequest 代表客户端的请求,用户通过Http协议访问服务器,HTTP请求中的所有信息会封装到HttpServletRequest ,通过HttpServletRequest 的方法,获取客户端的所有信息。
protected void doPost(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[] hobbies = req.getParameterValues("hobby");
System.out.println("-----------------------");
//后台接收中文乱码问题
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.toString(hobbies));
System.out.println("-----------------------");
//通过请求转发
resp.sendRedirect("/re/success.jsp");
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<h1>登录</h1>
<div style="text-align: center">
<form action="${pageContext.request.contextPath}/login" method="post">
用户名:<input type="text" name="username"> <br>
密码:<input type="password" name="password"> <br>
学校:
<input type="checkbox" name="hobby" value="清华">清华
<input type="checkbox" name="hobby" value="北大">北大
<input type="checkbox" name="hobby" value="浙大">浙大
<input type="checkbox" name="hobby" value="复旦">复旦
<input type="checkbox" name="hobby" value="武大">武大
<br>
<input type="submit">
</form>
</div>
</body>
</html>
7、Session、Cookie
7.1、会话
会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话。
有状态会话:可以在交互的同时,保持住状态(与会话的区别)。 此类场景的一个常见示例是我们正在使用的一个监视进程的会话。 理想情况下,我们想越快越好的向所监控的进程中插入任何传入事件,也希望尽快发现问题。
一个网站怎么证明你来过?
客户端 服务端
- 服务端给客户端一个信封,客户端下次访问服务器端带上信件就可以了;cookie
- 服务器登记你来过了,下次你来的时候我来匹配你;session
7.2、保存会话的两种技术
cookie
客户端技术(响应,请求)
session
服务器技术,利用这个技术可以保存用户的会话信息,我们可以把信息放在Session中
一些网站一次登录后,短时间内再访问就不用登录了。
7.3、Cookie
1、从请求中拿到cookie信息
2、服务器响应给客户端cookie
//cookie 服务器端从客户端获取
Cookie[] cookies = req.getCookies();
//判断cookie是否存在
if (cookies!=null){
out.write("你上一次访问的时间是:");
for (int i = 0; i <cookies.length ; i++) {
Cookie cookie = cookies[i];
//获取cookie的名字
if (cookie.getName().equals("lastLoginTime")){
//获取cookie的值
long lastLoginTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastLoginTime);
out.write(date.toLocaleString());
}
}
}else {
out.write("这是你第一次访问本站");
}
//服务给客户端响应一个coolie
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
//设置有效时间
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);
cookie一般保存在本地用户目录appdata下
- 一个Cookie只能保存一个信息;
- 一个web站点可以给浏览器发送多个cookie,最多存放20个Cookie;
- Cookie大小有限制4kb;
- 浏览器上限为300个Cookie
删除Cookie:
1、不设置有效时间,关闭浏览器自动失效;
2、设置有效时间为0;
7.4、Session*
什么是session:
- 服务器会给每一个用户(浏览器)创建一个session对象;
- 一个session独占一个浏览器,只要浏览器没有关闭,这个session就存在;
- 用户登录之后,整个网站它都可以访问;
//解决乱码
resp.setContentType("text/html;charset=utf-8");
//得到session
HttpSession session = req.getSession();
//给session中存东西
session.setAttribute("name",new Person("张三",18));
//获取session的ID
String id = session.getId();
//判断session是不是新创建的
if (session.isNew()){
resp.getWriter().write("session创建成功,ID:"+id);
}else {
resp.getWriter().write("session已经在服务器中存在了,ID:"+id);
}
//Session创建的时候做了什么事情
//Cookie jsessionid = new Cookie("JSESSIONID", sessionId);
//resp.addCookie(jsessionid);
Session和Cookie的区别:
- Cookie是把用户的数据写给用户的浏览器,浏览器保存(可以存多个)
- Session把用户的数据写到用户独占Session中,服务器端保存(保存重要信息,减少服务器资源浪费)
- session对象由服务器创建的
使用场景:
1、保存用户登录信息;
2、购物车信息;
3、在整个网站中经常会使用的数据,我们将它保存在session中;
会话过期:
自动
<session-config>
<!--1分钟 以分钟为单位-->
<session-timeout>1</session-timeout>
</session-config>
//手动注销session session.invalidate();