【JavaWeb】学习笔记(Tomcat)

JavaWeb

后端部分

1.Tomcat服务器

1.1 背景了解:

1.1.1 Web资源分类:

静态资源:html、css、js、txt、mp4视频、jpg图片等
动态资源:jsp页面、servlet程序、asp、php等
1.2 Tomcat服务器和servlet程序版本的对应关系
servlet版本2.5之前(目前市面上用的最多的版本)(XML配置)
servlet版本3.0之后(注解版本)
1.3 修改Tomcat默认端口号(8080)
Tomcat目录下的conf文件夹————>server.xml文件————>Connector标签里面有个port属性(1-65535)
修改完后重启Tomcat服务器后生效
http协议默认的端口号:80
1.4 Tomcat服务器部署方式

1.4.1 方式一

①在Tomcat目录下的webapps中新建工程文件夹
②在文件夹中拷贝IDEA中的工程文件(pages、static以及html等文件)
③在浏览器地址界面,输入地址http://localhost:8080/工程文件夹名/想要访问的文件……

1.4.2 方式二

①在Tomcat目录下的conf文件夹————>Catalina文件夹————>localhost文件夹————>新建工程名称.xml文件(可以直接新建一个txt文件,然后直接改后缀名为xml文件)
②在xml文件中编辑————><Context path="/自定义的xml文件名" docBase="Web工程文件存放的目录"/>
1.5 Tomcat默认访问的工程和默认访问的资源
在浏览器地址栏中输入:http://ip:port/  没有工程名的时候,默认访问的是ROOT工程
在浏览器地址栏中输入:http://ip:port/工程名/  有工程名但是没有资源名的时候默认访问index.html页面
1.6 IDEA与Tomcat服务器整合
①File——>Settings——>Build,Execution,Deployment——>Application Servers——>点击“+”,选择Tomcat Server
②选择Tomcat服务器的安装目录位置,可通过浏览配置
③工程中新建New Module(Java Enterprise)时选择Application Server中选择配置的服务器
1.7 新建动态Web工程
①New Module
②Java Enterprise——>Tomcat服务器版本——>勾选Web Application,默认勾选Create web.xml
③输入模块名,点击finish完成创建

Web目录结构解析:
①src 存放自己编写的java源代码
②web 专门用来存放web工程的资源文件,如:html界面,css文件,js文件等
③WEB-INF 受到服务器保护的目录,浏览器无法直接访问到此目录的内容
④一般在WEB-INF下新建一个lib文件夹用来存放jar包(IDEA中还需要自己配置导包)
⑤web.xml 是整个动态web工程的配置部署描述文件,可以在这里配置很多web工程的组建,比如:Servlet程序、Filter过滤器、Listener监听器,Session超时等等
1.8 Tomcat添加第三方jar包
方式一:可以通过与IDEA中类似的方法进行jar包的导入,即复制粘贴,右键add为library
方式二:
①File——>Project Structure——>Libraries——>“+”——>Java——>选择想要添加的jar包目录,创建一个类库,之后选择要给哪个模块使用,之后可以改类库的名字方便管理——>Apply
②Artifacts——>选择对应的类库——>Fix(Add xxx to artifact)
1.9 IDEA中如何部署web工程到Tomcat上运行
①建议修改web工程对应的Tomcat运行实例名称:点击页面上方运行按钮左边的下拉多选框,选择Edit Configurations...,之后建议将名称改成与当前web工程名称一致,之后Apply
②在Configurations中点击Deployment,通过"+"将需要部署的web工程添加到Tomcat运行实例中,"—"移除不需要的web工程,下面的Application context是默认生成的工程路径(这一步的主要目的是确认Tomcat实例中有你要部署运行的web工程)
③此时Configurations中的Server下,有个URL即启动Tomcat运行实例时,默认打开访问的地址
④此时点击运行按钮即可部署web工程到Tomcat上运行,当进行了修改之后,可以点击原先位置的update进行重新部署
1.10 其他细节说明
①一般Configurations中的Deployment中生成的默认工程路径会修改为与Web工程名称一致
②可以在Configurations中的Server中修改端口号,默认是8080
③可以在Configurations中的Server中的Open Browser修改运行使用的浏览器
④修改“资源热部署”——即页面修改后刷新界面修改就直接生效,在Configurations中的Server中的VM options下的On frame deactivation,将Do nothing修改为Update classes and resources,点击Apply生效,上面一栏的On 'Update' action中设置默认的那个弯箭头标志执行的操作类型,可以修改为重启服务器之类的操作

2.Servlet程序

2.1 什么是servlet?
①Servlet是JavaEE规范之一,就是接口
②Servlet是JavaWeb三大组件之一,三大组件分别是:Servlet程序,Filter过滤器、Listener监听器。
③Servlet是运行在服务器上的小程序,他可以接收客户端发来的请求并响应数据给客户端
2.2 Servlet程序的实现
①编写一个类去实现Servlet接口(Web工程中src文件夹新建一个Package,再新建class implements Servlet,通过ALT + insert——>Implement Methods重点关注service方法)
②实现Service方法,处理请求,并响应数据(如最简单的System.out.println("HelloServlet被访问了"))
③到web.xml中去配置servlet程序的访问地址
	添加<servlet>标签,包括servlet-name(起别名)以及servlet-class(对应的java类)
	添加对应的<servlet-mapping>标签,包括servlet-name(配置的url给哪个Servlet程序使用,和上面的对应)以及url-parttern(/xxx)

注意:
①servlet-class的类不要从com.xxx.xxx.xxx开始敲,直接输入类名就可以,否则无法对应到你想要的对应的那个java类,具体原因我也不清楚
②url-parttern中/xxx需要与java类有逻辑上的对应关系,否则可读性非常差
2.3 servlet的生命周期
①servlet构造器方法
②init初始化方法
第一次访问的时候调用,单例
③service方法
每次刷新都会重新调用该方法
④destroy销毁方法
销毁的时候调用该方法
2.4 servlet请求的分发处理(get和post请求)
get请求和post请求执行的操作不一样,但是service函数只有一个,因此需要判断请求类型区别对待,借助getMethod()方法

①ServletRequest的子类可以调用getMethod()方法,入口参数类型为ServletRequest类型,因此需要先通过其子类实例化:HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest
②String method = httpServletRequest.getMethod();
此外由于get和post执行的操作可能不止一个,在通过getMethod方法获取到请求类型后,通常在外面通过自定义函数的方式,进行封装,之后再进行调用。
2.5 通过继承HttpServlet实现servlet接口
一般开发过程中不直接从Servlet接口实现,而是从他的子类进行实现
①编写一个类去继承HttpServlet类(注意这里的是类不是接口)
②根据业务需要重写goGet或doPost方法(注意需要删除第一行的super.……否则会调用父类中的方法,网页会给出405的错误提示)
③到web.xml中配置Servlet程序的访问地址
2.6 IDEA直接创建Servlet程序
①src包右键New——>Servlet(如果没有再检查一下依赖)
②填写类名、包名、全包名自动生成

注意:
①去选下面的勾选项,不使用3.0以上版本的注解
②包名是从点击的resourceRoot开始算的,即从右键选中的文件夹开始算的,如果之前没有该包名会新建一个对应的包
③新建完成后仍需要在web.xml中配置地址
2.7 Servlet继承关系
Servlet————>接口,负责定义Servlet程序的访问规范
GenericServlet——>作为类,实现了Servlet接口,做了很多空实现,并持有一个ServletConfig类的引用
HttpServlet——>抽象类实现了service方法,实现了请求的分发处理,负责抛异常,提示不支持Get/Post请求
自定义的Servlet——>重写doGet和doPost方法
2.8 ServletConfig类
从名称上看就知道是Servlet程序的配置信息类
(在继承自Servlet的类中alter+insert即可快速引入接口函数,其中Init函数的入口参数中即有此servletConfig)
①可以获取Servlet程序的别名servlet-name的值
	servletConfig.getServletName();
②获取初始化init-param
	a.在web.xml中对应的<servlet>标签内,可定义<init-param>键值对,分别配置参数名和参数值
	b.通过servletConfig.getInitParameter(name:"xxx")获取对应的参数的值
③获取ServletContext对象
	servletConfig.getServletContext();获取ServletContext对象

补充说明:
①Servlet程序和ServletConfig对象都是由Tomcat服务器创建,我们使用即可
②Servlet程序默认是第一次访问的时候创建,ServletConfig是每个Servlet程序创建时,就创建一个对应的ServletConfig对象,因此每次获取ServletConfig对象的时候智能获取自身的,不能获取别的。getServletConfig()也能获取对象,但是获取到的ServletConfig对象是GenericServlet类中的,如果继承的类中重写Init()方法,需要super.init(config),否则会导致父类中的this.config = config操作丢失而引起子类中的空指针异常。
2.9 ServletContext对象
①是一个接口,表示上下文对象
②一个Web工程,只有一个ServletContext对象实例
③是一个域对象:可以像Map一样存取数据的对象,这里的域指的是存取数据的操作范围
④ServletContext会在Web工程部署启动的时候创建,在web工程停止的时候销毁

Map:存数据用put(),取数据用get(),删除数据用remove()
域对象:存数据用setAttribute(),取数据用getAttribute(),删除数据用removeAttribute()

四个作用:
①获取web.xml中配置的上下文参数context-param(属于整个Web工程的)
	ServletContext context = getServletConfig().getServletContext();
	context.getInitParameter(name:"xxxx")
②获取当前的工程路径,格式:/工程路径
	context.getContextPath();
③获取工程部署后在服务器硬盘上的绝对路径
	context.getRealPath("/")(/被浏览器解析为http://ip:端口号/工程名/ 映射到IDEA代码的web目录<br/>)
④像Map一样存储数据
	context.setAttribute(name:"xxx",object:"xxxx");
	context.getAttribute(name:"xxx");
	存储范围为整个web工程
2.10 Http协议
①GET请求
	a.请求行
		请求的方式:                    GET
		请求的资源路径:[+?+请求参数]
		请求的协议的版本号              HTTP/1.1
	b.请求头
		key:value组成,不同的键值对表示不同的含义
浏览器F12打开开发者调试界面,在提交表单内容的时候可以观察到请求行和请求头的内容,如2.11所述:

②POST请求
	a.请求行
		请求的方式:                    POST
		请求的资源路径:[+?+请求参数]
		请求的协议的版本号              HTTP/1.1
	b.请求头
		key:value组成,不同的键值对表示不同的含义
		空行
	c.请求体
		即发送给服务器的数据
2.11 常用的请求头类型
①Accept: text/html, application/xhtml+xml, image/jxr, */*(表示客户端可以接收的数据类型)
②Accept-Encoding: gzip, deflate(客户端可以接收的数据编码(压缩)格式)
③Accept-Language: zh-CN(客户端可以接收的语言类型)
④Connection: Keep-Alive(告诉当前服务器当前请求连接如何处理,还有一种为closed)
⑤Host: localhost:8080(请求的服务器IP和端口号)
⑥Referer: http://localhost:8080/servlet/test.html(当前请求是从哪里产生的)
⑦User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko(浏览器的信息)
⑧Content-Type:表示发送的数据类型
	application/x-www-form-urlencoded
		表示提交的数据格式是:name=value&name=value,然后对其进行url编码
		url编码就是把非英文的内容转换为:%xx%xx
	multipart/form-data
		表示以多段的形式提交数据给服务器(以流的形式提交,用于上传)
⑨Content-Length:表示发送的数据的长度
⑩Cache-Control:表示如何控制缓存(no-cache不缓存)
2.12 GET请求和POST请求怎么区分?
GET请求:
	①form标签,method="get"
	②a标签
	③link标签引入css
	④Script标签引入js文件
	⑤img标签引入图片
	⑥iframe引入html页面
	⑦在浏览器地址栏中输入地址后敲回车
POST请求:
	①form标签 method="post"
2.13 响应的Http协议介绍
a.响应行
	响应的协议和版本号  HTTP/1.1
	响应状态码          200
	响应状态描述符       OK
b.响应头
	key:value         不同的响应头有其不同的含义
	空行
c.响应体
	回传给客户端的数据
2.14 常见的响应状态码
200 表示请求成功
302 表示请求重定向
404 表示请求服务器已经收到了,但是你要的数据不存在(请求地址错误)
500 表示服务器已经收到请求,但是服务器内部错误(代码错误)
2.15 MIME类型说明(HTTP协议中的数据类型)
英文全称是:Mutipurpose Internet Mail Extensions 多功能Internet邮件扩充服务
类型格式:大类型/小类型
超文本标记语言文本  .html,.htm  text/html
普通文本           .txt        text/plain
RTF文本           .rtf        application/rtf(苹果和linux操作系统上常见,windows几乎不用)
GIF图形           .gif         image/gif
JPEG图形          .jpeg,.jpg   image/jpeg
au声音文件         .au         audio/basic
MIDI音乐文件       mid,midi    audio/midi,audio/x-midi
RealAudio音乐文件  .ra,.ram    audio/x-pn-realaudio
MPEG文件          .mpg,.mpeg   video/mpeg
AVI文件           .avi         video/x-msvideo
GZIP文件          .gz          application/x-gzip
TAR文件           .tar         application/x-tar
2.16 HttpServletRequest类
每次只要有请求进入Tomcat服务器,Tomcat服务器就回吧请求过来的HTTP协议信息解析好封装到Request对象中,然后传递到service方法(doGet和doPost)中供我们使用,我们可以通过HttpServletRequest对象获取到所有请求的信息

常用方法有:
①getRequestURI()              获取请求的资源路径
②getRequestURL()              获取请求的统一资源定位符(绝对路径)
③getRemoteHost()              获取客户端的ip地址
④getHeader()                  获取请求头
⑤getParameter()               获取请求参数
⑥getParameterValues()         获取请求的参数(多个值的时候使用)
⑦getMethod()                  获取请求的方式(GET还是POST)
⑧setAttribute(key,value)      设置域数据
⑨getAttribute()               获取域数据
⑩getRequestDispatcher()       获取请求转发对象

继承自HttpServlet类的doGet和doPost方法的入口参数中有HTTPServletRequest对象req
req.getRequestURI() => /工程名/资源路径
req.getRequestURL() => http://ip:端口号 + URI
req.getRemoteHost() => 127.0.0.1即localhost,如果使用真实的ip地址访问,得到的就是真实的客户端ip地址
req.getHeader(name:"User-Agent") => 可以获取发送请求的浏览器参数
req.getParameter(name:"xxx") => 获取参数(用String接收即可)
req.getParameterValues(name:"xxx") => 获取多个参数(用String[]接收,打印时Arrays.asList(xxx))

注意:
post请求在提交表单的时候会出现中文乱码的问题,解决办法:在获取请求参数之前,通过setCharacterEncoding("UTF-8")方法解决乱码问题。必须在获取任何请求参数之前使用,在获取任何一个参数之后再调用就会失效。
2.17 请求的转发(servlet1 => servlet2)
服务器收到请求后,从一个资源跳转到另一个资源的操作
流程:req.getParameter(name:"……")(检查资料) => req.setAttribute(name:"xxx",value:"xxx")(盖章) => req.getRequestDispatcher("/servlert2")(问路) => xxxDispatcher.forward(req,resp)(跳转)

特点:
①浏览器地址栏没有变化
②他们是一次请求
③他们共享req域中的数据(Attribute)
④可以转发到WEB-INF目录下(直接访问的话浏览器禁止访问)
⑤是否可以访问工程以外的资源?不能!
2.18 base标签的作用
用于设置页面相对路径工作时参照的地址

使用base标签的原因:
使用a标签进行跳转的时候"/a/b/c.html",通过"../../index.html"跳转回去没有问题,当使用请求转发的方式进行跳转的时候跳转过去没问题,通过servlet-mapping实现跳转。但是跳转回来的时候由于../../是相对路径,与浏览器当前的地址有关,回退到错误的地址导致跳转回来失败,这时候即可以使用base标签使之从base标签开始使用相对路径跳转。

一般base标签放在title标签下面,如:
<base href="http://localhost:8080/07_servlet/a/b/c.html"> 最后面的"c.html"可以省略,但是/不能省略,不省略才是目录。
2.19 "/"不同的解析结果
如果被浏览器解析,得到的地址是:http://ip:端口号/
	<a href="/">斜杠</a>
如果被服务器解析,得到的地址是:http://ip:port/工程路径
	①<url-pattern>/servlet1</url-pattern>
	②servletContext.getRealPath("/")
	③request.getRequestDispatcher("/")
特殊情况:response.sendRedict("/") => 这是把斜杠发送给浏览器解析,得到的是浏览器解析的结果 => 请求重定向
2.20 HttpServletResponse类
与HttpServletRequest类相似,每次请求进来,Tomcat服务器都会创建一个Response对象传递给Servlet程序去使用,通过设置该对象设置返回给客户端的信息

两个输出流:
字节流    getOutputStream()    常用于下载(传递二进制数据)
字符流    getWriter()          常用于回传字符串(常用)
两个流只能二选一,否则会报错

默认响应的编码为ISO-8859-1,此时解析服务器返回给客户端的中文会出现乱码问题,解决办法:
方法一:
①通过resp.setCharacterEncoding("UTF-8")设置服务器编码为UTF-8
②通过响应头设置客户端的浏览器也使用UTF-8字符集解析页面:resp.setHeader(name:"content-Type",value:"text/html;charset=UTF-8")
需要同时设置服务器和浏览器的字符集,少一个都不可以
方法二:
//这一行代码会同时设置服务器和客户端都使用UTF-8字符集,还设置了响应头
resp.setContentType("text/html;charset=UTF-8")
注意:方法二一定要在获取流对象之前调用才有效
2.21 请求重定向
是指客户端给服务器发请求,然后服务器告诉客户端,给你一下新地址,你去新地址访问。(因为之前的地址可能已经被废弃)
①告知客户端此地址已搬迁 ==>> 响应码 302	
②并且告知新的地址      ==>>  响应头 Location

方法一:
resp.setStatus(302) ==>>  表示重定向
resp.setHeader(name:"Location",value:"新地址") ==>>  设置响应头,告知新地址
方法二:(推荐使用)
resp.setRedirect(location:"新地址")

特点:
①地址栏会发生变化
②两次请求
③不共享req的Attribute域数据
④不能访问WEB-INF下的资源
⑤可以访问工程外的资源(如访问百度)
2.22 JavaEE三层架构(SSH和SSM框架的由来)
①Web层/视图展现层 ==>> Sevlet程序、SpringMVC
	a.获取请求参数,封装成Bean对象
	b.调用service层处理业务
	c.响应数据给客户端、请求转发、重定向
②Service业务层 ==>> Spring框架
	a.处理业务逻辑
	b.调用持久层保存到数据库
③Dao持久层 ==>>  Jdbc、DbUtils、Mybatis、Hibernate
	Dao持久层,只负责跟数据库交互,执行CRUD操作

分层的目的是为了实现解耦,降低代码的耦合度,方便项目后期的维护和升级
	①Web层  com.atguigu.web/servlet/controller
	②Service层  com.atguigu.service Service接口包  +  com.atguigu.service.impl Service接口实现类
	③Dao层  com.atguigu.dao Dao接口包  +  com.atguigu.dao.impl Dao接口实现类
	④实体Bean对象  com.atguigu.pojo/entity/domain/bean  JavaBean类
	⑤测试包  com.atguigu.test/junit
	⑥工具类包  com.atguigu.utils
2.23 书城项目第二阶段
①创建项目所需的数据库和表
②编写数据库表所对应的JavaBean对象(属性、getter&setter、toString、Structure)
③编写工具类JdbcUtils
④编写BaseDao
⑤编写UserDao和测试 => 接口

注意:
①在编写工具类JdbcUtils时,需要用到jdbc.properties配置文件,尚硅谷视频教程中是放在src目录下的,但是由于用的IDEA版本不同,构建的项目结构也有所不同,查CSDN后发现,只有将jdbc.properties文件放在/src/main/resources里面才能使getResourceAsStream()方法读取到,否则就会报空指针异常,据CSDN上反映,后面将工程部署在web上时可能会出现新找不到文件的问题。
根本原因是需要将存放property配置文件的文件夹右键mark directory as resource root

3.JSP相关

虽然有很多有过开发经验的工程师都建议,尽量不要使用JSP,但是,作为物联网领域学习的新人来说,还是要了解一下JSP的,不然遇到老项目维护用的是JSP怎么办呢,最关键的是先学习整套流程,等到自己真切体会到JSP的不便之处的时候相信才是真的懂JSP了,这个时候再去学新技术,如themeleaf或者VUE等可能才会更加深刻。

3.1 JSP
全称:java server pages
主要作用是代替Servlet程序回传html页面的数据
servlet回传html页面数据是一件非常繁琐的事情,开发和维护的成本都极高
JSP的本质还是Servlet程序,Tomcat会将JSP页面翻译成Java源文件,将其编译成为.class字节码程序
3.2 JSP的头部page指令
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
①language属性     表示jsp翻译之后是什么语言文件,目前只支持java
②contentType属性  表示jsp返回的数据类型是什么,也是源码中response。setContentType()参数值
③pageEncoding     表示当前jsp页面文件本身的字符集
④import           跟java源代码中一样,用于导包,

⑤autoFlush        设置当out输出流缓冲区满了之后,是否自动刷新冲级区。默认值是true。
⑥buffer           设置out缓冲区的大小,默认是8kb

⑦errorPage属性    设置当jsp页面运行出错时,自动跳转去的错误页面路径

⑧isErrorPage      设置当前jsp页面是否是错误信息页面,默认是false,如果是true可以

⑨session          设置访问当前jsp页面,是否会创建HttpSession对象,默认是true
⑩extend           设置jsp翻译出来的java类默认继承值
3.3 声明脚本
<%! xxx %>
①声明类属性
	<%!
		private Integer id;
		private static Map<String,Object> map;
	%>
②声明static静态代码块
	<%!
		static {
			map = new Hashmap<String,Object>();
			map.put("key1","value1");
			map.put("key2","value2");
		}
	%>
③声明类方法
	<%!
		public int abc(){
			return 12;
		}
	%>
④声明内部类
	<%!
		public static class A(){
			private Integer id = 12;
		}
	%>
3.4 表达式脚本
<%= xxx %>
特点:
①所有的表达式脚本都会被翻译到_jspService()中
②表达式脚本都会被翻译成为out.print()输出到页面上
③由于表达式脚本翻译的内容都在_jspService()方法中,所以在_jspService()方法中的对象都可以直接使用
④表达式脚本中的表达式不能以分号结尾
如:
<%=12%>
<%=12.12%>
<%="xxx"%>
<%=map%>
<%=request.getParameter("username")%>
3.5 代码脚本(思考为什么需要将for循环代码分开写)
<%
	for(int j = 0; j < 10; j++){
%>
<%	
		System.out.println(j)
	}
%>

练习一:输出九九乘法口诀:
在这里插入图片描述练习二:输出有10个学生的信息表:
在这里插入图片描述

3.6 jsp中的三种注释
①html注释  <!-- xxx -->
②java注释  //xxx 或 /* xxx */
③jsp注释   <%-- xxx --%>
在代码脚本中使用java注释方式,而jsp注释可以用于jsp页面的所有位置
3.7 jsp的九大内置对象
request      请求对象
response     响应对象
pageContext  jsp的上下文对象
session      会话对象
application  ServletContext对象
config       ServletConfig对象
out          jsp输出流对象
page         指向当前jsp的对象
exception    异常对象
3.8 jsp四大域对象
pageContext  (PageContextImpl类)      当前jsp页面范围内有效
request      (HttpServletRequest类)   一次请求内有效
session      (HttpSession类)          一个会话范围内有效(打开浏览器访问服务器,直到关闭浏览器)
application  (ServletContext类)       整个web工程范围内都有效(只要web工程不停止,数据都在)

四个域都可以存储数据,在使用上有优先顺序,依次从小到大读取
pageContext => request => session => application

在这里插入图片描述
由于jsp翻译之后,底层源代码都是使用out来进行输出,所以在一般情况下,在jsp页面统一使用out来进行输出,避免打乱页面输出内容的顺序(这是针对上图中response。getWrite().write(“xxx”)也可以输出的层面来说的),即在getWriter.write()和out之间选out。

out.write()  输出字符串没问题
out.print()  输出任意数据都没有问题(都转换为字符串后调用的write输出)
在使用out时,统一使用out.print()来进行输出

在这里插入图片描述

3.9 静态包含与动态包含
<%@ include file=""%> 就是静态包含
file属性指定要包含的jsp页面的路径
地址中第一个斜杠 / 表示为 http://ip:port/工程路径/  映射到代码的web目录

静态包含的特点:
①静态包含不会翻译被包含的jsp页面
②静态包含其实是包被包含的jsp页面的代码拷贝到包含的位置执行输出
如:
<%@ include file="/include/footer.jsp"%>

<jsp:include page=""></jsp:include> 这是动态包含
page属性是要包含的jsp页面的路径
动态包含也可以像静态包含一样,把被包含的内容执行输出到包含位置

动态包含的特点:
①动态包含会把包含的jsp页面翻译成java代码
②动态包含底层代码使用如下的代码去调用被包含的Jsp页面执行输出
	JspRuntimeLibrary.include(request,response,"/include/footer.jsp",out,false);
③动态包含,可以传递参数:
如:
<jsp:include page="/include/footer.jsp">
	<jsp:param name="username" value="bbj"/>
	<jsp:param name="password" value="root">
</jsp:include>
一般情况下都使用静态包含
3.10 jsp标签转发
<jsp:forword page=""></jsp:forward> 是请求转发标签,功能是请求转发
page属性设置请求转发的路径
如:
<jsp:forward page="/scope2.jsp"></jsp:forward>

请求转发示意:(一整套下来是一次请求)
在这里插入图片描述

3.11 Listener监听器
JavaWeb的三大组件之一,JavaWeb的三大组件:Servlet程序、Filter过滤器、Listener监听器
Listener它是JavaEE的规范,就是接口
作用:监听某种事物的变化,通过回调函数,反馈给客户(程序)去做一些相应的处理

servletContextListener可以监听ServletContext对象的创建和销毁
servletContext对象在web工程启动的时候创建,在web工程停止的时候销毁
监听到创建和销毁之后都会分别调用ServletContextListener监听器的方法反馈
步骤如下:
①编写一个类去实现ServletContextListener
②实现其两个回调方法
③到web.xml中去配置监听器
3.12 EL表达式

Expression Language 表达式语言
主要是代替jsp页面中的表达式脚本在jsp页面中进行数据的输出(因为EL表达式在输出数据的时候,要比jsp的表达式脚本要简洁很多)

<body>
	<%
			request.setAttribute("key"."值");
	%>
	表达式脚本输出key的值是:
	<%= request.getAttribute("key1")==?null"":request.getAttribute("key1")%><br/>
	EL表达式输出key的值是:${key1}
</body>

以上代码段显示出了使用jsp表达式脚本和使用EL表达式写法下的复杂度对比

EL表达式的格式是:${表达式}
EL表达式在输出null值的时候,输出的是空串,jsp表达式脚本输出null值的时候,输出的是null字符串

在这里插入图片描述
注意:EL表达式输出的值并不是属性本身的值,而是属性对应的“读”方法的值,即使没有定义该属性,定义了该属性为名的“get”方法即可,如果是Boolean属性的则对应“is”方法

3.12.1 关系运算
在这里插入图片描述
3.12.2 逻辑运算
在这里插入图片描述3.12.3 算数运算
在这里插入图片描述

3.13 empty运算

用于判断一个数据是否为空,如果为空,则输出true,不为空则输出false

①值为null值的时候,为空
②值为空串的时候,为空
③值是Object类型数组,长度为0的时候、
④list集合,元素个数为0
⑤map集合,元素个数为0
3.14 三元运算
表达式1?表达式2:表达式3
如果表达式1的值为真,返回表达式2的值,如果表达式1的值为假,返回表达式3的值
3.15 “.”运算和[]中括号运算
.运算可以输出Bean对象中某个属性的值
[]中括号运算,可以输出有序集合中某个元素的值
并且[]中括号运算,还可以输出map集合中key里含有特殊字符的key的值(即当key中含有特殊字符时,点运算不再适用,需要使用中括号运算)
如:${ map['a.a.a'] } <br>
3.16 EL表达式的11个隐含对象
pageContext        PageContextImpl          可以获取jsp九大内置对象
pageScope          Map<String,Object>       可以获取pageContext域中的数据
requestScope       Map<String,Object>       可以获取Request域中的数据
sessionScope       Map<String,Object>       可以获取Session域中的数据
applicationScope   Map<String,Object>       可以获取ServletContext域中的数据

param              Map<String,String>       可以获取请求参数的信息
paramValues        Map<String,String[]>     获取多个请求参数的值的时候使用

header             Map<String,String>       可以获取请求头的信息
headerValues       Map<String,String[]>     获取多个请求头值的情况

cookie             Map<String,Cookie>       可以获取当前请求的Cookie

initParam          Map<String,String>       可以获取在web.xml文件中配置的<context-param>上下文参数

3.16.1 EL获取四个特定域中的属性

pageScope         ==>>  pageContext域
requestScope      ==>>  Request域
sessionScope      ==>>  Session域
applicationScope  ==>>  ServletContext域
当四个域都有数据时可以通过此方式输出特定域的内容,否则会按照域的大小进行搜索

3.16.2 pageContext对象
在这里插入图片描述

企业中的简化写法:
<%
	pageContext.setAttribute("req",request);
%>
${ req.scheme }<br>

3.16.3 EL表达式其他隐含对象的使用

param&paramValues:
在这里插入图片描述header&headerValues:
在这里插入图片描述cookie:
在这里插入图片描述initParam:
在这里插入图片描述需要注意,“<”和“>”需要转换表达形式

3.17 JSTL标签库

EL表达式主要是为了替换jsp中的表达式脚本,而JSTL标签库是为了替换代码脚本

使用步骤:

①先导入JSTL标签库的jar包
	taglib-standard-impl-1.2.1.jar
	taglib-standard-spec-1.2.1.jar
②使用taglib指令引入标签库,如::<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

3.17.1 set标签

<c:set scope="page" var="abc" value="abcValue"/>

相当于:域对象.setAttribute(key,value);
scope 属性设置保存到哪个域
	page表示PageContext域(默认值)
	request表示Request域
	session表示Session域
	application表示ServletContext域
var属性值设置key值是多少
value属性设置值

3.17.2 if标签(只能做单路判断)

<c:if test="${ 12! = 12 }">
	<h1> 12等于12 </h1>
</c:if>

3.17.3 多路判断(<c:choose><c:when><c:otherwise>)

<c:choose>
	<c:when test="${ requestScope.height > 190 }">
		<h2> 小巨人 </h2>
	</c:when>
	……
	<c:otherwise>
		<h2> 剩下的情况 </h2>
	</c:otherwise>
</c:choose>
注意事项:
①标签里不能使用html注释,要使用jsp注释
②when标签的父标签一定要是choose标签(即无论何时想要使用when标签做多路判断,一定要先试用choose标签)

3.17.4 forEach标签(遍历)

①遍历1到10,输出
<c:forEach begin="1" end="10" var="i">
	<tr>
		<td> 第${i}行 </td>
	</tr>
</c:forEach>
begin属性设置开始的索引
end属性设置结束的索引
var属性表示循环的变量(当前遍历到的数据)
for(int i =1; i <10; i++)

②遍历Object数组
<%
	request.setAttribute("arr",new String[]{''18640541354","18688886666","18699998888"})
%>
<c:forEach items="${ requestScope.arr }" var="item">
	${ item }<br>
<c:forEach>
items表示遍历到的数据
var表示当前遍历到的数据
for(Object item:arr)

③遍历Map集合
<%
	Map<String,Object> map = new HashMap<String,Object>();
	map.put("key1","value1");
	map.put("key2","value2");
	map.put("key3","value3");
	request.setAttribute("map",map)
%>
<c:forEach items="${ requestScope.map }" var="entry">
	<h1>${entry.key} = ${entry.value}</h1>
</c:forEach>
相当于:for(Map.Entry<String,Object> entry : map.entrySet()){}

④遍历List集合
<%
	List<Student> studentList = new ArrayList<Student>();
	for(int i = 1;i <=10; i++){
		studentList.add(new Student(……))
	}
	request.setAttribute("stus",studentList);
%>
<c:forEach items="${requestScope.stus}" var="stu">
	${ stu }<br>
</c:forEach>

属性总结:
items     表示遍历到的集合
var       表示遍历到的数据
begin     表示遍历的开始索引值
end       表示结束的索引值
step      属性表示遍历的步长值
varStatus 属性表示当前遍历到的数据的状态
其中varStatus中的状态由Java源码中的接口LoopTagStatus定义,通过以下方式调用:
在属性中定义 => varStatus="stus" 
通过“.”调用 => stus.Current/stus.Index/stus.First……

在这里插入图片描述

3.18 文件上传与下载

3.18.1 文件上传

①要有一个form标签,method = post请求
②form标签的encType属性值必须为multipart/form-data值
③在form标签中使用input type = file添加上传的文件
④编写服务器代码(Servlet程序)接收,处理上传的数据
encType = multipart/form-data表示提交的数据,以多段(每一个表单项一个数据段)的行驶进行拼接,然后以二进制流的形式发送给服务器

示例如下:
在这里插入图片描述
文件上传时发送的http协议解析
在这里插入图片描述
服务器接收数据时以流的形式接收:

ServletInputStream inputStream = req.getInputStream();

byte[] buffer = new byte[1024000];
int read = inputStream.read(buffer);
System.out.println(new String(buffer,0,read));

服务器处理接收到的数据用到的包有Commons-fileupload.jar和commons-io.jar包,由Apache提供,常用类如下:
在这里插入图片描述
在这里插入图片描述
示例:

protected void doPost(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
	//1.先判断上传的数据是否是多端数据(只有是多段的数据,才是文件上传的)
	if(ServletFileUpload.isMultipartContent(req)){
		//创建FileItemFactory工厂实现类
		FileItemFactory fileItemFactory = new DiskFileItemFactory();
		//创建用于解析上传数据的工具类ServletFileUpload类
		ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
		try{
			//解析上传的数据,得到每一个表单项FileItem
			List<FileItem> list = servletFileUpload.parseRequest(req);
			//循环判断,每一个表单项,是普通类型还是上传的文件
			for(FileItem fileItem:list){
				if(fileItem.isFormField()){
					//普通表单项
					System.out.println("表单项的name属性值:" + fileItem.getFieldName());
					//参数UTF-8,解决乱码问题
					System.out.println("表单项的value属性值:" + fileItem.getString("UTF-8"));
				}
				else{
					//上传的文件
					System.out.println("表单项的name属性值:" + fileItem.getFieldName());
					System.out.println("上传的文件名:" + fileItem.getName());
					fileItem.write(new File("e:\\" + fileItem.getName()));
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

3.18.2 文件下载
在这里插入图片描述

protected void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
	//1.获取要下载的文件名
	String downloadFileName = "2.jpg";
	//2.读取要下载的文件内容(通过ServletContext对象可以读取)
	ServletContext servletContext = get ServletContext();
	//3.获取要下载的文件类型
	String mimeType =servletContext.getMimeType("/file/" + downloadFileName);
	System.out.println("下载的文件类型:" + mimeType);
	//4.在回传前,通过响应头告诉客户端返回的数据类型
	resp.setContentType(mimeType);
	//5.还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
	//Content-Disposition响应头,表示收到的数据怎么处理
	//attachment表示附件,表示下载使用
	//filename 表示指定下载的文件名
	resp.setHeader("Content-Disposition","attachment;filename=" + downloadFileName);
	InputStream resourceAsStream = servletContext.getResoueceAsStream("/file/" + downloadFileName)
	//6.获取响应的输出流
	OutputStream outputStream = resp.getOutputStream();
	//7.把下载的文件内容回传给客户端
	//8.读取输入流中全部的数据,复制给输出流,输出给客户端
	IOUtils.copy(resourceAsStream,outputStream);
}

下载文件中含有中文名称时:

①(谷歌和IE浏览器)需要进行url编码,转化为%xx%xx%xx……的编码,之后可以识别和显示中文文件名
②火狐浏览器需要进行Base64编码

url编码:

resp.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode("中国.jpg","UTF-8"))

Base64编码:
在这里插入图片描述
Base64解码:
在这里插入图片描述
编码之后内容变为:
在这里插入图片描述上图中xxxx内容部分浏览器会隐藏,因为内容太多,视觉上很不好,可通过下列代码调取:

"filename==?UTF-8?B?" + new BASE64Encoder().encode("中国.jpg".getBytes("UTF-8")) + "?="
中间的部分即xxxx内容
3.19 书城第三阶段(代码优化)

3.19.1 将Html改为jsp

①首先在页面顶部添加page指令
	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
②然后refactor => rename 重命名为.jsp后缀
③使用IDEA搜索替换引用到的.html为.jsp

在这里插入图片描述
在这里插入图片描述
3.19.2 抽取公共内容

将jsp页面中大量重复的部分复制到新的jsp页面中,将原来的的地方通过静态包含的方式替换
<%@ include file="/pages/common/head.jsp"%>

3.19.3 动态获取Base路径
Beanutils和logging
在这里插入图片描述
3.19.3 表单提交失败的错误回显

①Servlet程序修改:
在这里插入图片描述
②Jsp页面修改:
在这里插入图片描述
在这里插入图片描述
例:验证码错误回显:
在这里插入图片描述
例:用户名已存在错误回显:
在这里插入图片描述
总而言之,需要回显的数据保存到request域中

3.19.4 合并login和regist

实际项目开发中是一个模块对应一个servlet程序

通过action的value值来进行分别处理
在这里插入图片描述
在这里插入图片描述

将注册登录功能单独写成函数,在对应的分支中进行方法调用,便于维护,结构更加清晰
Login和regist函数直接复制doPost方法,修改方法名称即可,因为需要的入口参数一致。
在这里插入图片描述
再通过反射优化if else代码:(即直接通过invoke调用目标业务、方法)
在这里插入图片描述
将UserServlet.class.getDeclaredMethod方法替换为如下内容:

this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class)

将invoke内的内容替换为:

(this,req,resp)

再将各自servlet程序里面相同步骤的任务进行抽取,抽取成BaseServlet程序:
视频示例中是将各自servlet程序中的doPost方法抽取到BaseServlet中:
在这里插入图片描述3.19.4 数据的封装和抽取BeanUtils的使用

BeanUtils工具类,他可以一次性的把所有请求的参数注入到JavaBean中

BeanUtils中的populate方法注入:
在这里插入图片描述
将上述代码部分封装为WebUtils的工具类:

User user = new User();
WebUtils.copyParamToBean(req,resp);

注入的本质是找到对应参数的写方法(SET方法)

再进行优化,将HttpServlet中的req写成Map类型的Value,因为httpservlet对应的API只有在WEB层才有对应的API可以进行处理,除此之外的DAO层以及Service层都没办法处理,而Map类型三层都可以处理。
在这里插入图片描述
再进行优化,可以将以下两行代码合成一行:
在这里插入图片描述
需要的操作如下:

①修改方法的返回值类型为Object,return bean;
②强制类型转换

在这里插入图片描述
在这里插入图片描述
再进行优化,可以通过使用泛型,省去强制类型转换这一步骤:
在这里插入图片描述
可以省去强制类型转换步骤:
在这里插入图片描述

注意事项

1.xxx.html文件新建在webapp文件夹下即可,注意,不要在WEB-INF里面建,里面存放web.xml配置文

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值