JAVA WEB入门
前言:之前一开始的时候就没有好好地学习javaweb,因为直接是从框架着手的,现在在实习的时间里,看着时间寒酸充裕,所以打算一个星期把javaweb搞完,学习的资源是B站上的狂神说JAVA的视频。
1.基本概念
1.1 前言
web开发:
-
web、网页的意思。
-
静态web
- html, css
- 提供给所有人看的数据始终不会发生变化!
-
动态web:
- 淘宝,几乎所有的网站都离不开动态web
- 提供给所有人看的数据始终会发生变化,每个人在不同的时间,不同的地点看到的信息各不相同!
- 技术栈:servlet/jsp, asp, php
在Java中,动态网页的开发统称为Javaweb技术
1.2 web应用程序
Web应用程序是一种可以通过Web页面访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件。
一个web页面都会存在某一个计算机上,通常情况下,组成这个web应用程序的相关文件都会放在同一个目录下,然后将这些文件运行在tomcat中,这样便能访问对应的页面和使用相应的功能了。
1.3 静态页面和动态页面的区别
静态页面:
静态 WEB指的以*.htm、*.html 为后缀的网页,这些网页的访问只是从服务器上读取这
些内容,然后返回给客户端浏览器解析呈现在用户面前。不过静态WEB也有缺点,所有用户看到的效果一样,无法实现与用户动态交互:不能登录验证,连接数据库等。
动态页面
web页面可以动态更新,所有用户看到的页面可以同步显示(一致的)。使用最多的是javaScript来实现动态的页面(数据的交互)
2、web服务器
2.1 技术讲解
ASP(动态服务器页面):
- 微软:国内最早流行的就是ASP
- 在HTML中嵌入了VB的脚本
- 在ASP开发中,基本一个页面都有几千行的业务代码,页面机器混乱
- 维护成本高,代码冗余大。
PHP
- 开发速冻很快,功能很强大,跨平台,代码比较简单
- 无法承载访问量大的情况
JSP、Servlet
- sun公司主推的B/S架构
- 基于Java语言的(所有的大公司,或者是一些开源的组件,都是Java写的)
- 可以承载三高(高并发,高性能,高可用)问题带来的影响。
- 其实就是ASP的改良。加强市场强度;
2.2 web服务器
概念
:服务器也叫做伺服器,是提供计算服务的设备 。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担并且保障服务的能力。服务器的构成主要包括处理器、硬盘、内存、系统总线等。
2.3 Tomcat
Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。由于有了Sun 的参与和支持,最新的Servlet 和JSP 规范总是能在Tomcat 中得到体现,Tomcat 5支持最新的Servlet 2.4 和JSP 2.0 规范。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache 服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。
诀窍是,当配置正确时,Apache 为HTML页面服务,而Tomcat 实际上运行JSP 页面和Servlet。另外,Tomcat和IIS等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Apache服务器。目前Tomcat最新版本为9.0.37。(来自百度百科)
下载tomcat(此教程省略)
文件结构:
启动关闭tomcat:
在bin文件夹下面有一个startup.bat的文件,打开它即表示启动成功;shutdown.bat表示关闭
配置:
在config中的server.xml文件中可以配置tomcat启动的默认端口号和主机名,在本地电脑目录的C:\Windows\System32\drivers\etc\hosts文件中可以更改电脑回环ip地址的域名(127.0.0.1 ——> localhost)
谈谈在网址栏中输入一个url回车后访问的过程:
-
检查输入的域名是否在本机C:\Windows\System32\drivers\etc\hosts文件中存在这个域名的ip映射;
- 如果有,则直接访问这个ip地址。
- 如果没有,则去上级的DNS服务,返回这个域名的ip地址。
- 获得ipd地址之后,本地与目标ip地址建立TCP三次握手连接。
- 建立好tcp连接后按照http(s)协议开始向目标ip发送http请求,同样会收到回复。
- 通信完成之后,断开tcp连接(四次挥手)。
2.4 发布一个web网站
在本地发布一个网站的时候,网站的资源必须放在tomcat安装目录的webapps文件夹下,比如系统默认启动的时候的页面资源是这样的:
接下来我们仿照上面的目录结构重新在webapps目录下创建一个目录。网站资源的目录结构一般包含以下的几部分
--webapps: tomcat服务器的web目录
-ROOT:默认的页面资源
-achao:自定义的网站目录
-WEB-INF
-classes : java程序
-lib:web应用所依赖的jar包
-web.xml:网站配置文件
-index.html:默认的首页
-static
-css
-style.css
-js
-img
......
然后地址栏上输入http://localhost:8080/achao/即可访问我们自己发布的网址。默认的首页就是index.html,这个文件要自己创建。
3、HTTP
3.1 什么是HTTP
http是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII码形式给出;而消息内容则具有一个类似MIME的格式。这个简单模型是早期Web成功的有功之臣,因为它使开发和部署非常地直截了当。
3.2 HTTP的两个时代
**HTTP1.0 和 HTTP2.0 **
主要的区别:
- 2.0时代使用了多路复用的技术,做到了同一个连接请求并发处理多个请求,而且并发请求的数量比之前大了好几个数量级。
- header的压缩。2.0使用了hpack算法对header的数据进行了压缩,这样数据体积小了,在网上传输的速度就会更快。
- 服务器推送。在浏览器请求之前,免得客户端再次创建连接发送请求到服务端获取,这样客户端可以直接从本地加载这些资源,不用再通过网络。
更多http的详细讲解可以参考这篇博客:
4、Servlet
4.1 Servlet简介
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。
Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。但是相比于 CGI,Servlet 有以下几点优势:
- 性能明显更好。
- Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
- Servlet 是独立于平台的,因为它们是用 Java 编写的。
- 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
- Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。
4.2 Hello Servlet
- 创建一个普通的maven项目。最好先创建一个父module,这样之后的练习都通过创建子module来练习不同的例子。避免重复导入依赖。
- 需要导入的依赖:
<dependencies>
<!-- servlet依赖的jar包start -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- servlet依赖的jar包start -->
<!-- jsp依赖jar包start -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
</dependencies>
- 创建一个子module, 可以直接使用idea中webapp模板。之后创建一个类,继承HttpServlet接口,重写doget和doPost的方法。
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter(); // 获取响应流
writer.print("Hello Servlet"); // 响应流输出
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
- 编写Servlet映射
为什么要映射:因为我们写的是Java程序,但是浏览器通过连接web服务器,所以我们需要在web服务器中注册我们写的servlet,除此之外,还需给它一个浏览器能够访问到的路径。
在webapp/WEB-INF/web.xml文件中进行如下的配置:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 注册一个servlet-->
<servlet>
<servlet-name>achao</servlet-name>
<servlet-class>com.achao.HelloServlet</servlet-class>
</servlet>
<!-- servlet映射的请求路径-->
<servlet-mapping>
<servlet-name>achao</servlet-name>
<url-pattern>/achao</url-pattern>
</servlet-mapping>
</web-app>
- 配置tomcat:
注意上面的标注部分
- 点击idea中的通过tomcat启动项目。启动项目之后,按照我上面的tomcat配置和xml中的配置文件,我可以访问到的这个servlet应用程序的网络路径是:http://localhost:8080/hello_servlet/achao。访问的显示效果如下:
至此,我的第一个servlet程序运行成功!
4.3 servlet运行原理
servlet是由web服务器调用,web服务器在收到浏览器请求之后,会判断这个请求是不是servlet中的请求,这样的话就是用servlet中的响应。具体的步骤可以分为以下的几步:
- 浏览器向服务器发送http请求,如上面的例子,浏览器请求响应http://localhost:8080/hello_servlet/achao;
- 服务器收到请求之后,检查浏览器请求的url中是否为servlet请求,于是去找web.xml中是否拥有这样的servlet映射,可以找到”achao”这个路径对应者注册的一个名叫“achao”的servlet,于是将浏览器的请求交给servlet处理。
- 此时servlet生成两个对象,一个是reques对象,另一个是response对象,分别用来解析浏览器的请求和返回消息。当然这个请求是分为get/post/put/delete等等的,不同的请求方式进入不同的方法。这里我们进入的是doGet方法。
- doGet执行完成之后,将结果返回给tomcat,之后tomcat将该信息“转发”给浏览器。
- 此时一个完成的servlet请求运行结束。
这个过程个人感觉和代理模式有点相似,在这里浏览器是客户,web服务器是代理,servlet是代理者。不过与代理模式不同的是,servlet在其中的角色做了很多工作。
4.4 servlet的生命周期
看了菜鸟教程中的servlet生命周期,带上自己的理解,做下记录。
-
Servlet 初始化后调用
init ()
方法。
可以从Servlet中的源码看到,它的实现类中init(ServletConfig config)参数,而ServletConfig 类中拥有获取一些基本属性的方法,比如ServletContext。
-
Servlet 调用
service()
方法来处理客户端的请求。
这个方法从HttpServlet中的源码可以得知,servlet将从web容器中获得的封装的request进行判断,它请求的类型决定由那个doXXX()方法去处理。
-
Servlet 销毁前调用
destroy()
方法。
这个方法源码上没有任何信息,我猜应该是执行这个方法后是切断自身的引用,好让JVM尽快的回收。(因为JVM一般判断一个对象是否可以回收使用的是可达性分析算法和引用计数法)
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
4.5 Mapping的问题
- 一个Servlet可以指定一个映射路径。
- 一个servlet可以指定多个映射路径。
- 一个servlet可以指定通用映射路径。
- 可以指定一些后缀或者前缀的映射路径。
- 当一个固定的映射路径属于一个通配的映射路径的时候,优先判断是否为该固定的映射路径。
4.6 servletContext
web容器在启动的时候,它会为每个web程序(servlet请求)都创建一个对应的servletContext对象,它代表了当前的web应用。它的作用主要有以下的几个方面:
-
共享数据:用于不同的servlet之间的数据交流。
- 创建两个servlet程序:
public class ServletSetAttr extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取当前servlet所属的context对象 ServletContext context = this.getServletContext(); String name = new String("achao"); // 在上下文中设置一个键值对的属性 context.setAttribute("name", name); } } public class ServletGetAttr extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletContext context = this.getServletContext(); // 获取context中的属性 String name = (String) context.getAttribute("name"); System.out.println(name); // 打印输出 } }
- 在web.xml文件中配置servlet的路径映射
<servlet> <servlet-name>setAttr</servlet-name> <servlet-class>com.achao.ServletSetAttr</servlet-class> </servlet> <servlet-mapping> <servlet-name>setAttr</servlet-name> <url-pattern>/setAttr</url-pattern> </servlet-mapping> <servlet> <servlet-name>getAttr</servlet-name> <servlet-class>com.achao.ServletGetAttr</servlet-class> </servlet> <servlet-mapping> <servlet-name>getAttr</servlet-name> <url-pattern>/getAttr</url-pattern> </servlet-mapping>
- 启动tomcat,依次访问这两个路径,可以从控制台的输出得到,这个context中的属性。
2.获取初始化参数
通过在web.xml中设置context中的初始化属性,可以在servlet中获取到这个初始化属性。
web.xml:
<servlet>
<servlet-name>getAttr</servlet-name>
<servlet-class>com.achao.ServletGetAttr</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getAttr</servlet-name>
<url-pattern>/getAttr</url-pattern>
</servlet-mapping>
<context-param>
<param-name>jdbc</param-name>
<param-value>jdbc:mysql://localhost:3306/redis</param-value>
</context-param>
servlet中获取
public class ServletGetAttr extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
String jdbc = context.getInitParameter("jdbc");
System.out.println(jdbc); // 打印输出jdbc:mysql://localhost:3306/redis
}
}
3.请求转发
使用
context.getRequesDispatcher("转发的路径")
,可以获取一个转发的对象,这个对象中有两个方法,一个是forward(),一个是include()方法,这两种方法都是要传入reques和response参数,唯一的区别就是,前者执行完成之后,直接将相关的信息转发给目标的servlet程序,本程序后面的代码不会执行,相当于直接跳出了本地程序;后者的话把请求转发给了对应的servlet去了,但是它后面的程序依然会执行。
注意,转发的时候,浏览器的地址栏显示的还是一开始访问的那个路径
与重定向的区别:
请求转发的是由中间人直接把请求信息转发给了某个程序,这对于浏览器来说是透明的,只需发送一次请求。
重定向是由中间人告诉浏览器,你需要的资源在另一个路径,于是浏览器重新访问另一个路径,这对于浏览器来说要发送两次请求。
4.读取资源文件
-
新建一个properties文件,里面添加两个属性:
name = achao password = 123456
-
使用
context.getResourceAsStream(filepath)
方式获取这个资源文件的输入流。 -
创建一个Properties对象,使用它的load()方法将上面的输入流作为参数传递进去。
-
使用properties的getProperty()方法可以根据一个字符串获取到资源文件中的属性。
简单地说就是将一个资源文佳转化成为一个输入流,然后将这个输入流封装到properties对象中去,这样的话,properties对象就可以使用对应的方法获取到这个资源文件中设置的属性了。
4.7 HttpServletReponse
负责向浏览器发送数据的方法
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
负责向浏览器发送响应头的方法
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentLengthLong(long var1);
void setContentType(String var1);
返回的状态码信息
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
......
常见应用:
- 向浏览器输出信息
- 返回一个输出流,让客户端获取下载资源
public class FileServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 要提供给客户端下载的图片的地址
String realPath = "D:\\IdeaProjects\\javaweb\\servlet-02\\src\\main\\resources\\headportrait.jpg";
System.out.println("获取到要下载的文件路径:" + realPath);
// 提供给客户端的图片文件名
String filename = realPath.substring(realPath.lastIndexOf("\\"));
// 设置响应头:这是一个附件,设置文件名和编码格式
resp.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
// 获取该图片资源的输入流
FileInputStream input = new FileInputStream(realPath);
int len = 0;
byte[] buffer = new byte[1024];
// 获取响应输出流
ServletOutputStream out = resp.getOutputStream();
// 将本地文件的输入流转换成响应的输出流
while ((len = input.read(buffer)) > 0){
out.write(buffer, 0, len);
}
input.close();
out.close();
}
}
// 最后别忘了在web.xml设置路径映射。浏览器访问这个路径,会直接下载资源
- 验证码功能的实现
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);
// 获得这个图片的图像,进行绘画
Graphics graphics = image.getGraphics();
// 设置颜色以及填充区域
graphics.setColor(Color.white);
graphics.fillRect(0, 0, 80, 20);
// 设置颜色,画一个字符串
graphics.setColor(Color.BLUE);
graphics.setFont(new Font(null, Font.BOLD, 20));
graphics.drawString(makeNum(), 0, 20);
// 设置相应的内容为一张图片
resp.setContentType("image/jpeg");
// 让浏览器不要缓存
// resp.setDateHeader("expores", -1);
// resp.setHeader("Cashe-Control", "no-cashe");
// resp.setHeader("Pragma", "no-cashe");
// 将这张图片写入到response的输出流
ImageIO.write(image, "jpg", resp.getOutputStream());
}
// 获取随机数
public 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");
}
String s = sb + num;
return s;
}
}
// 别忘了在web.xml设置路径映射
效果显示:
4.8 HttpServletRequest
HttpServletRequest代表客户端请求,用户通过HTTP协议访问服务器,Http请求中地所有信息会被封装到HTTPServletRequest,通过这个类的方法,我们可以获取到客户端的所有信息。
5、Cookie、Session
会话(Session)
跟踪是Web程序中常用的技术,用来
跟踪用户的整个会话
。常用的会话跟踪技术是Cookie与Session。
Cookie通过在客户端记录信息确定用户身份
,
Session通过在服务器端记录信息确定用户身份
。
两者的区别:
- cookie是客户端的技术,session是服务端的行为。
- cookie不是很安全,因为cookie通常是让服务器去检查里面的键值对信息,这种信息可以伪造。
- session相对来说是比较安全的,它将一个session_id发送给客户端,并用它来查找客户端的状态。
- session对存储的数据量没有限制,可以保存更为复杂的数据结构。
- cookie保存的数据不能超过4k,很多浏览器限制一个站点最多保存20个cookie。
- session很容易失效,用户体验比较差。
5.1 cookie
在servlet中,可以从请求中拿到其携带的cookie,而在响应中可以设置cookie,servlet对cookie做相应的判断操作。代码如下
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置编码
req.setCharacterEncoding("UTF-8");
resp.setCharacterEncoding("UTF-8");
// 拿到客户端提交的cookie
Cookie[] cookies = req.getCookies();
PrintWriter out = resp.getWriter();
// 判断客户端是否来过(即请求的cookie中是否携带服务器设置的cookie信息)
boolean state = false;
// 遍历客户端携带的cookie
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookie.getName() != null && cookie.getName().equals("lastLoginTime")) {
state = true;
long lastLoginTime = Long.parseLong(cookie.getValue());
Date date = new Date(lastLoginTime);
out.print("您上一次访问的时间是:");
out.print(date.toLocaleString());
}
}
}
// 响应返回一个指定的cookie
Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis() + "");
cookie.setMaxAge(24*60*60);
resp.addCookie(cookie);
if (!state) {
out.print("这是您第一次访问");
}
}
注意:
如果没有设置cookie的过期时间,当浏览器关闭的时候,cookie就会失效
5.2 session
HttpSession中常用的一些方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EjulKbO3-1606396435808)(C:\Users\achao\AppData\Roaming\Typora\typora-user-images\image-
.png)]
使用session的例子
public class SessionServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
// 得到session
HttpSession session = req.getSession();
// 设置响应的内容格式
resp.setContentType("text/html; charset=utf-8");
PrintWriter out = resp.getWriter();
Person person = null;
if (session.isNew()){
person = (Person) session.getAttribute("achao");
out.write("存在最新的session, id=" + session.getId());
}else {
out.write("服务器中已经存在了sessiion了,id为:" + session.getId());
}
if (person != null){
out.print("age:" + person.getAge());
out.print("name:" + person.getName());
}
// 在session中存入一个实体类
session.setAttribute("achao", new Person("achao", "18"));
}
}
浏览器访问显示
通过F12我们可以发现,浏览器中存在一个这样的cookie键值对:JSESSIONID : 5FC19222A6371CE2F40105E35F00B3A8,这个value就是对应的session_id,可见,浏览器通过提供这个id,在服务器上找到对应的session,取到相应的属性。这样就可以解释了同一个网站的不同的子页面可以保持用户的登陆状态(主要就是用户请求中携带了一个value为session_id的cookie。
配置session的生命周期可以载web.xml中配置:
<session-config>
<!--设置 15分钟后自动失效-->
<session-timeout>15</session-timeout>
</session-config>
可以在Java代码中使用下面的方法手动注销session
session.invalidate()
6、JSP
6.1 什么是JSP
Java Server Pages: java服务端页面,也和Servlet一样,用于动态web技术!
最大的特点:
- 写JSP就像在写HTML
-
区别
- HTML只给用户提供静态数据
- JSP页面中可以嵌入JAVA代码,为用户提供动态数据
6.2 JSP原理
在tomcat的目录下这是我的电脑目录
C:\Users\achao\.IntelliJIdea2019.2\system\tomcat\Unnamed_javaweb\work\Catalina\localhost\session_war\org\apache\jsp\index_jsp.java
, webapp目录下的index.jsp生成了一个java代码文件,通过阅读这个代码来看,
这个类继承了一个HttpJspBase
类,而HTTPBase是继承了HttpServlet类,所以我们可以得出结论:
浏览器在访问web资源的时候,最终访问的就是一个servlet!
JSP本质就是一个Servlet!
该Java中主要分为以下的几个方法:
// 初始化
public void _ispInit();
// 销毁
public void _jspDestory();
// JSPService
public void _jspService(HttpServletRequest request, HttpServletResponse response);
1、判断请求
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
}
2、内置了一些对象
final javax.servlet.jsp.PageContext pageContext; // 页面上下文
javax.servlet.http.HttpSession session = null; // session
final javax.servlet.ServletContext application; // applicationContext
final javax.servlet.ServletConfig config; // config
javax.servlet.jsp.JspWriter out = null; // out
final java.lang.Object page = this; // 当前
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null; // pageContext
3、关键的执行代码块
response.setContentType("text/html"); // 设置响应的类型
// 拿到上述内置的对象
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
// 以HTML的格式输出页面内容
out.write("<html>\n");
out.write("<body>\n");
out.write("<h2>Hello World!</h2>\n");
out.write("</body>\n");
out.write("</html>\n");
原理流程图
6.3 JSP基本语法
jsp中支持Java的所有语法,
所需依赖
<!-- servlet依赖的jar包start -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- jsp依赖jar包start -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!-- JSTL表达式依赖-->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
<!-- standard标签库-->
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.1</version>
</dependency>
JSP表达式
<%= new Date()%> // 获取到一个时间,并把这个信息原封不动地输出到页面
JSP片段
<%
for (int i = 0; i < 10; i++) {
out.print("<h2>"+ i + "</h2>");
}
%>
// 片段嵌套
<%
for (int i = 0; i < 10; i++) {
%>
<h2>片段嵌套<%= i%></h2>
<%
}
%>
JSP声明
// jsp声明
<%!
public int each(int i){
for (int j = 0; j < i; j++) {
System.out.println("循环了" + j + "次");
}
return i;
}
%>
<%= new Date()%>
// jsp片段调用声明
<%
out.print(each(20));
%>
片段和声明的区别:
- 片段在生成Servlet程序的时候,里面的Java代码都是生成在_jspService方法中的。
- 声明在生成Servlet程序的时候,声明的变量作为生成类的属性,方法定义在在_jspService方法的前面,也就是声明中的变量和方法可以给片段中的代码使用。
JSP指令
JSP指令用来设置与整个JSP页面相关的属性。JSP中有三种指令标签:
<%@ page …%>: 定义页面的依赖属性,比如脚本语言,error页面,缓存需求
<%@ include … %>: 包含其他文件。例如下面的例子,实现页面的分块。
<%@include file="head.jsp"%>
<%="这是主体"%>
<%@include file="footer.jsp"%>
<%@ taglib … %>:引入标签库的定义,可以是自定义的标签。
6.4 九大内置对象
PageContext:提供了对jsp页面所有对象以及命名空间的访问。
Request:封装了来自客户端、浏览器的各种信息。
Reponse:封装了服务器的响应信息。
Session:用来保存会话信息。也就是说,可以实现在同一用户的不同请求之间共享数据。
Application(ServletContext):代表了当前应用程序的上下文,可以在不同的用户之间共享信息。
config(ServletConfig):封装了应用程序的配置信息。
out:用于向客户端、浏览器输出数据。
page:指向了当前jsp页面本身。
exception:封装了jsp页面执行过程中发生的异常和错误信息。
jsp四大作用域和九大内置对象
这篇文章我看着讲得很是详细。推荐阅读。
6.5 JSP标签、JSTL标签、EL表达式
JSP标签
JSP标签也称之为Jsp Action(JSP动作)元素,它用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护。
jsp的常用标签有以下三个
- <jsp:include >标签
- <jsp:forward >标签
- <jsp:param >标签
导入依赖:
<!--jsp依赖-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
</dependency>
编写代码
<body>
<%--带参数转发到某个页面--%>
<jsp:forward page="/jsp5.jsp">
<jsp:param name="name" value="Hayden-Wong"></jsp:param>
<jsp:param name="age" value="23"></jsp:param>
<jsp:param name="sex" value="Male"></jsp:param>
</jsp:forward>
</body>
JSTL标签
JSTL标签的使用是为了弥补HTML标签的不足,它自定义许多标签可供使用,标签的功能和Java代码相同。
类别
- 核心标签(最常用)
- 格式化标签
- SQL 标签
- XML 标签
- JSTL 函数
EL表达式
语法
在JSP中访问模型对象是通过EL表达式的语法来表达。所有EL表达式的格式都是以“**
∗
∗
”
表
示
。
例
如
,
{ }**”表示。例如,
∗
∗
”
表
示
。
例
如
,
{ userinfo}代表获取变量userinfo的值。当EL表达式中的变量不给定范围时,则默认在page范围查找,然后依次在request、session、application范围查找。也可以用范围作为前缀表示属于哪个范围的变量,例如:${ pageScope. userinfo}表示访问page范围中的userinfo变量。
变量
EL存取变量数据的方法很简单,例如:${username}。它的意思是取出某一范围中名称为username的变量。
因为我们并没有指定哪一个范围的username,所以它会依序从Page、Request、Session、Application范围查找。
假如途中找到username,就直接回传,不再继续找下去,但是假如全部的范围都没有找到时,就回传。
用途
- 获取数据
- 执行运算
- 获取web开发的常用对象
7、MVC三层架构
1. 简述
在上面的联系中,我们大概知道了一个请求发送到Web服务器的时候,大概会走哪些流程,为了直观,在下面花了一个图:
上面所示就是经典的Servlet+JSP+Java Been 模型。
但是为了更好的对模块进行解耦,上面JAVA WEB开发模型中还有一个很重要的缺点,就是所有的业务处理都交给了Servlet程序,包括数据库的事务,这样的话会让代码显得异常臃肿。而且随着NoSQL的强势崛起,需要访问的数据库不是单一的,这样的话就 迫切地要将业务层与Servlet程序分离,于是出现了下面的Spring MVC架构:
Controller
: 负责调用业务层处理web容器映射过来的用户请求,并返回响应。
Service
:控制层与数据访问层的桥梁,负责处理业务。
Dao
: 服务层与数据库的桥梁,负责连接数据库,提供对数据库的操作,对象关系型映射。
上面的三个层是基本地MVC架构模型,当然一个完成的请求的的过程应该涉及到下面的流程:
Spring mvc的更多内容建议查看这篇文章:
8、过滤器(Filter)
8.1 简述
过滤器是一个程序,它先于与之相关的servlet或JSP页面运行在服务器上。过滤器可附加到一个或多个servlet或JSP页面上,并且可以检查进入这些资源的请求信息。在这之后,过滤器可以作如下的选择:
①以常规的方式调用资源(即,调用servlet或JSP页面)。
②利用修改过的请求信息调用资源。
③调用资源,但在发送响应到客户机前对其进行修改。
④阻止该资源调用,代之以转到其他的资源,返回一个特定的状态代码或生成替换输出。
**简单来说,filter就是一个servlet程序,它将请求和响应经过一定的人为处理之后,再将他们发送给对应的servlet或者web容器。**下面的图很好的说明了filter的作用位置。
8.2 简单实现
首先我们注册一个简单的servlet程序,程序代码如下,映射的路径有两个,一个是/filter和/filterUsed.下面的servlet程序的输出因为没有设置相应的编码值,最后输出到的页面肯定是乱码的。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
out.write("过滤器过滤后消息变成不是乱码的状态了");
}
添加filter
// 实现Filter接口
public class Filter implements javax.servlet.Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
// 这个方法就是用来过滤的
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset:utf-8");
filterChain.doFilter(request, response); // 表示过滤后通过
}
@Override
public void destroy() {
}
}
在web.xml中配置这个filter需要过滤的路径
<filter>
<filter-name>filtered</filter-name>
<filter-class>com.achao.filter.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filtered</filter-name>
<url-pattern>/filterUsed</url-pattern>
</filter-mapping>
9、监听器(Listener)
9.1 简述
监听器就是一一个实现了特定接口的Java类,这个Java类用于监听另一个Java类的方法调用或者属性的改变。当被监听对象发生上述事件后,监听器某个方法将会立即被执行。用来监听其他对象的变化的。
建议监听器方面的教程看这篇文章
——
servlet监听器快速入门