在学习web技术后能够完成复杂B/S系统
所谓B/S结构其实就是上图的一个三层结构,
除了B/S 结构(只需要一个浏览器即可,例如访问百度网站),还有一个C/S 结构(客户端和服务器的交互,需要安装客户端软件,例如qq等等)
特点:
分布式:
中间件(两个独立的系统之间可以互相通信)
MQ:(Message Queue)
Spring data Solr:索引库(将数据库)
Spring data Redis:缓存技术
高并发
使用http服务器集群(集群搭建)
海量数据
负载均衡,高可用
基于面向服务架构:SOA(大型电商系统)
程序之间的数据传输通讯 程序之间的数据传输通讯
配置文件 配置文件config.xml
存储数据,充当小型数据库 存储数据,充当小型数据库
规范数据格式,是数据具有结构性,易读易处理 是数据具有结构性,易读易处理
固定格式:
三大管理工具:Ant(早期)、Maven(最常用)、gradle
创建maven项目,必须在pom.xml文件引入相关的jar包的依赖
在pom.xml文件里导入第三方的文件,在这个xml文件里用固定语法来导入你所下载的第三方文件
新建项目的时候选择用maven,点击next…(下面是过程中的几个参数)
groupId:组织名 公司域名反写
Atrified:项目名
Version:版本号(用默认的就行)
首先我们得下载apache-maven-3.3.9这个软件
在我们的C:\Users\Laptop.m2\repository这个目录下都有一个本地仓库,使用maven工具时就不用再手动导入各种jar包,占用内存也比较大;
但我们需要自己弄一个本地仓库(其实就是一个包含大量jar包的文件夹,下载下来后存放到E盘,不要存放到C盘,因为比较大占内存),大家可以自己去网上寻找一个进行下载;
下载好maven这个软件后,我们还得配置它的环境变量
- 找到maven的安装路径,复制它
- 在系统变量里新建一个变量命名为:M2_HOME ,它的值为上面复制的地址
- 再在系统变量的Path下添加:%M2_HOME%\bin
配置好环境变量后,就可以使用cmd来执行maven的一些命令
在IDEA新建一个maven项目后,我们的项目是默认在C:\Users\Laptop.m2\repository这个本地仓库上 进行搜索的,但我们说了,我们自己创建了一个本地仓库(拥有大量jar包),所以就不需要引入系统C盘自带的那个仓库,所以我们在IDEA中进行下面一个操作设置,将原本默认的仓库路径改为我们安装的apache-maven-3.3.9目录下conf\settings.xml ,这时下面一行的Local repository就会自动改为我们下载的那个仓库的路径;
(前提:我们得打开apache-maven-3.3.9\conf \ settings.xml这个xml文件,然后找到里面的 E:\develop\repository 这条语句,中间的路径得设置为我们下载的那个仓库得地址 )
进行上面设置后,就可以对我们的仓库进行了关联;
到了这里还没有结束,我们还需要在我们项目下的pom.xml文件里导入本地依赖 ,因为我们只是将那个仓库进行了关联,不可能把里面的jar包全部导入吧,所以需要什么jar包还得在pom.xml这个文件中进行导入依赖,导入格式如下:
<dependencies>
dependencies>
导入坐标后,刷新maven的结构(右边管理栏点击maven,点击刷新按钮),在我们的项目目录External Libraries 下就可以看到我们导入的jar包;
观察下面这张图,dom解析就是将xml文件中的各种信息提取出来;
[外链图片转存失败(img-SKd5eWt2-1563255979284)(C:\Users\Laptop\AppData\Local\Temp\1558855039786.png)]
基于第三方的jar包(dom4j:dom for java )
可以打开E:\Web编程\Web软件和jar包\dom4j-1.6.1\docs\index.html(我的电脑下下载dom4j的位置)这个网页中查看dom4j的使用文档
定义:使用底层流的方式:SAXReader对象将Xml文档进行封装,将每一个标签封装成标签对象(Node)
url----两种方式,一种是相对路径(常用),一种是绝对路径
相对路径:ClassLader:类加载器读取文件
//创建解析器对象
SAXReader reader = new SAXReader();
//读取文件
Document doc = reader.read(demo1.class.getClassLoader().getResource("contact.xml"));
Element rootElement = doc.getRootElement();
System.out.println(rootElement);
Element conElement = rootElement.element("contact");
System.out.println(conElement);
package www.yy.web;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.List;
/**
* @Author : YangY
* @Description :
* @Time : Created in 9:45 2019/5/26
*/
public class demo1 {
public static void main(String[] args) throws Exception{
//创建解析器对象
SAXReader reader = new SAXReader();
//读取文件
Document doc = reader.read(demo1.class.getClassLoader().getResource("contact.xml"));
Element rootElement = doc.getRootElement();
System.out.println(rootElement);
//获取根节点下的子标签:element("标签名称"):默认获取第一个子标签对象
Element conElement = rootElement.element("contact");
System.out.println("--------------获取指定节点的属性(方式一:通过属性名称获取)-------------------------------");
String value = conElement.attributeValue("id");
System.out.println("conElement id :"+value);
System.out.println("--------------获取指定节点的属性(方式二:通过属性对象获取)-------------------------------");
Attribute attribute = conElement.attribute("id");
System.out.println(attribute.getName()+" : "+attribute.getValue());
System.out.println("--------------获取根节点下指定名字的所有节点列表----------------");
List<Element> list = rootElement.elements("contact");
for(Element e: list) {
System.out.println(e);
}
System.out.println("-----------------获取根节点下的所有子节点列表-----------------------");
List<Element> list2 = rootElement.elements();
for(Element e: list2) {
System.out.println(e);
}
System.out.println("-----------------获取孙节点-------------------");
Element nameElement = rootElement.element("contact").element("name");
System.out.println(nameElement);
System.out.println("---------------获取指定标签的文本内容:方式一(首先获取标签)------------------------------------");
String text = rootElement.getText();
System.out.println(text);
System.out.println("---------------");
String text2 = nameElement.getText();
System.out.println(text2);
//方式2:
System.out.println("-------方式二:通过父标签对象.elementText(\"子节点名称\"):获取子节点的文本内容(重点方法)------");
System.out.println(conElement.elementText("name"));
System.out.println(conElement.elementText("phone"));
System.out.println(conElement.elementText("gender"));
}
}
输出:
org.dom4j.tree.DefaultElement@14c265e [Element:]
--------------获取指定节点的属性(方式一:通过属性名称获取)-------------------------------
conElement id :001
--------------获取指定节点的属性(方式二:通过属性对象获取)-------------------------------
id : 001
--------------获取根节点下指定名字的所有节点列表----------------
org.dom4j.tree.DefaultElement@1a4f24f [Element:]
org.dom4j.tree.DefaultElement@99a589 [Element:]
-----------------获取根节点下的所有子节点列表-----------------------
org.dom4j.tree.DefaultElement@1a4f24f [Element:]
org.dom4j.tree.DefaultElement@99a589 [Element:]
org.dom4j.tree.DefaultElement@dd8dc3 [Element:]
-----------------获取孙节点-------------------
org.dom4j.tree.DefaultElement@103e736 [Element:]
---------------获取指定标签的文本内容:方式一(首先获取标签)------------------------------------
张三
-------方式二:通过父标签对象.elementText(“子节点名称”):获取子节点的文本内容(重点方法)------
张三
13466668888
男Process finished with exit code 0
package www.yy.write;
import com.sun.org.apache.xpath.internal.operations.String;
import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @Author : YangY
* @Description : document对象输出到硬盘上,目的是:修改/删除 标签和属性
* @Time : Created in 10:58 2019/5/26
*/
public class Demo1 {
public static void main(java.lang.String[] args)throws Exception {
//1)读contact.xml
Document doc = new SAXReader()
.read(Demo1.class.getClassLoader()
.getResource("contact.xml")) ;
//使用XMLWriter对象
//创建OutputStream
OutputStream out = new FileOutputStream("E:\\bit资料大全\\Web编程\\新建文本文档.xml") ;
/**
* 输出的细节:OutputFormat对象 :指定xml文件的输出格式
*/
//紧凑格式:部署上线:xml文件都会在一行,节省xml文件空间
// OutputFormat format = OutputFormat.createCompactFormat() ;
//优雅格式:测试时使用(默认的)
OutputFormat format = OutputFormat.createPrettyPrint();
//设置输出的编码
//format.setEncoding("utf-8");
XMLWriter writer = new XMLWriter(out,format) ; //也可以只有out这一个参数,format默认优雅格式
//将doc对象写出到硬盘
writer.write(doc);
//释放资源
writer.close();
}
}
xpath技术:可以快速定位到某个具体的标签
常用的两个方法:
selectSingleNode(“xpath表达式”); ------>返回某个元素(Node),可以强转为Element
selectNodes(“xpath表达式”); ------->返回List;
语法:
public class Demo {
public static void main(String[] args) throws Exception{
Document document = new SAXReader().read(Demo.class.getClassLoader().getResource("contact.xml"));
String path = null;
//path = "//contact-list";
//path = "//contact";
//path = "//name[text()='李四']";
path = "//contact[@id=001]";
Element ele = (Element) document.selectSingleNode(path); //需要强转,Node是Element的爷爷接口
System.out.println(ele);
List<Element> list = document.selectNodes(path);
for(Element element:list) {
System.out.println(element);
}
}
}
输出:
org.dom4j.tree.DefaultElement@1be847c [Element:]
org.dom4j.tree.DefaultElement@1be847c [Element:] Process finished with exit code 0
三要素:
SAXParser:SAX解析器
定义一个类 extends DefaultHander 事件处理程序
并发访问理论值只有500个,所以不适用于大型电商服务器
这是一个开源免费的,所以很多小公司喜欢用它
Servlet-api.jar
Jsp-api.jar
在tomcat的conf 目录下的logging.properties 属性文件下,进入这个文件:
找到47行,将utf-8改为gbk,如下:
java.util.logging.ConsoleHandler.encoding = jbk
在cmd中输入命令:netstat -ano
运行后找到 TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 6488 这一行(参数跟我这不一样)
找到这一行后查看对应得PID参数,再输入命令:tasklist
接下来在显示出来的列表中查找对应PID参数为6488(这里是)的对应应用程序名
然后打开资源管理器
servlet简介
开发Servlet的基本步骤
自定义一个类继承于HttpServlet
重写doGet(HttpServletRequest requst,HttpServletResponse respons)方法
接收前台的传递参数
跳转页面
配置Servlet:在web.xml文件中
<servlet>
<servlet-name>和当前Servlet的类名一致servlet-name>
<servlet-class>包名.类名servlet-class>
servlet>
//servlet映射信息的配置
<servlet-mapping>
<servlet-name>和当前servlet的类名一致servlet-name>
<url-pattern>类名url-pattern>
servlet-mapping>
maven的web标准结构((IDEA中,且不勾选骨架的时候必须按照下面格式来创建工程))
main
Java:写Java代码
resource:存储的资源配置文件 xml,properties;
webapp
WEB—INF (文件)
web.xml (里面必须要放表头,支持3.1的版本,支持注解)
引入web.xml的初始信息(在我们不勾选骨架的时候才需手动导入,勾选了骨架自动就会导入) :
在tomcat的文件下的webapp中有五个例子,我们可以随便点开一个去寻找其中的web.xml文件,然后将其表头信息复制过来,信息如下:
<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_3_1.xsd"
version="3.1"
metadata-complete="true">
web-app>
配置好上面信息后,我们就在Java包下可以创建一个自己的包了,包里自定义一个.Java文件,在我们写的类时,规定得继承HttpServlet这个类,但这又是第三方的,所以又得导入jar包;
在maven中引入 jsp-api.jar 和 servlet-api.jar
Tomcat中内置两个jar包
Maven引入本地仓库中jsp和servlet,jar包
在pom.xml中版本冲突解决方案
(解决tomcat和本地仓库的jar包冲突: 依赖范围)
scop的作用:表明引入第三方的jar包只是一个额外提供,但是最终参与部署的还是tomcat中的包
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>scope>
dependency>
这里要讲的方法其实就是省去前面所讲方法的一些步骤,用IDEA工具来快速创建servlet;
我们新建一个Java文件时,如果像以前那样直接新建一个Java文件,我们得手动来让这个类继承自HttpServlet,然后还得在web.xml文件中配置servlet和servlet-mapping这两项,现在我们只需要新建的时候不再选用javaclass而是选用(倒数第三个选项)servlet,注意选择这个后把默认勾选的去掉,然后点击完成,就自动生成一个继承自HttpServlet的类,而且在web.xml中把servlet已经配置好了,现在只需要再配置servlet-mapping ;
默认下面那个是勾选上的,一般不进行勾选;
完成上面操作后,在类中IDEA已经帮我们自动继承了HttpServlet,自动覆写了doGet和doPost方法,一般情况下,我们在doPost方法中调用doGet,我们要实现的业务逻辑都在doGet中去完成,模板如下:
public class ServletTestMy extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//在这里写代码,实现业务逻辑
}
}
语法:(在web.xml中配置)
不写的时候默认值为1,一般从2开始,数字越大,优先级越低
<servlet>
<servlet-name>LifeServletservlet-name>
<servlet-class>com.yy.life.LifeServletservlet-class>
<load-on-startup>2load-on-startup>
servlet>
原本不配置这条语句的时候,当我们启动tomcat时(此时还停留在主页,没有访问url),servlet对象没有被初始化和创建,当我们配置这条语句(为2)后,我们一启动tomcat后就创建和初始化了servlet对象;
初始化:public void init(ServletConfig config) throws ServletException;
服务方法:protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
服务方法:在访问servlet默认执行service方法(要根据不同的提交方式判断的)
意思是就算我覆写了doXX(代表多种提交方法,例如doGet、doPost等等)方法,运行tomcat后,执行的还是service方法,不会执行doXX方法,因为再service的源码中就已经覆盖了所有的doXX方法;
所以我们一般不会覆写service方法,试想如果你覆写了service方法后,你怎么写你的业务呢,你要实现些啥都会被service方法覆盖,所以一般覆写我们具体的doXX方法来实现自己的业务;
而最常用的doXX方法为doGet和doPost方法;
http://localhost:8080/life
在web工程下的web.xml中的mapping中查找是否存在url-pattern (你在地址栏输入的路径),如果存在则找到对应的servlet配置,通过反射来执行 ;(在servlet配置中有class路径嘛,通过class.foeName(“class路径”)来进行反射访问)
<servlet>
<servlet-name>LifeServletservlet-name>
<servlet-class>com.yy.life.LifeServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>LifeServletservlet-name>
<url-pattern>/lifeurl-pattern>
servlet-mapping>
通过反射来获取当前Servlet的Class对象
解析Servlet中的方法,给用户响应
注意:访问servlet:先是动态(web.xml) ,再是静态 (webapp下寻找是否存在xxx.html/jsp…)
1.Servlet的特点:单实例,多线程 ⭐
对于多线程,所以存在安全问题
校验多线程安全问题的标准:
- 查看当前是否为多线程环境
- 是否存在共享数据
- 是否有多条语句堆共享数据进行操作
解决方案:使用同步代码块(这里就是Java只是啦)
一个web工程中可以有多个config对象
举个栗子:
当我们要读取文件中的内容时,按照以前的方法,则会采取流的方式来进行文件读取,代码如下:
//读取一个磁盘上的文件内容:e:/aaa.txt :讲过内容输出到控制台
BufferedReader br = new BufferedReader(new FileReader("e:/aaa.txt")) ;
String line = null ;
while((line=br.readLine())!=null){
System.out.println(line);
}
这里有一个缺陷,当我们要读取的文件的路径发生改变的时候,我们需要改变这里的源代码的路径,这样会显得比较麻烦;
先在web.xml中添加init-param标签,如下:
<servlet>
<servlet-name>ConfigDemoservlet-name>
<servlet-class>com.bite.d_config.ConfigDemoservlet-class>
<init-param>
<param-name>pathparam-name>
<param-value>e:/aaa.txtparam-value>
init-param>
<init-param>
<param-name>path1param-name>
<param-value>e:/bbb.txtparam-value>
init-param>
servlet>
在HttpServlet的父类GenericServlet类中提供了这样一个获取ServletConfig对象的方法:
public ServletConfig getServletConfig() {
return config;
}
ServletConfig config = this.getServletConfig();
String path = config.getInitParameter("path");
BufferedReader br =
new BufferedReader(new FileReader(path)) ;
String line = null ;
while((line=br.readLine())!=null){
System.out.println(line);
}
}
有些参数需要提供给当前项目的所有servlet使用,此时需要配置全局参数
首先在web.xml中配置如下:(这里的代码不再是包含在某个servlet块之内,而是独立的)
<context-param>
<param-name>encodingparam-name>
<param-value>utf-8param-value>
context-param>
同理,要想在servlet中获取到这个全局参数,首先得获取到ServletContext这个对象,然后再调用它的方法来进行获取:
public class ContextDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1)获取全局管理者对象
ServletContext context = this.getServletContext();
String encoding = context.getInitParameter("encoding");
System.out.println(encoding);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
在了解重定向之前,我们需要先了解甚麽是http封装请求对象和响应对象 ,虽然前面讲了那么多,但始终还是不太理解浏览器端和服务器端是如何进行交互的,下面通过这张图可以一目了然:
所谓重定向,先来看下面的一段实现重定向的简单代码:
public class ContextDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 重定向的原理:
* 1)响应头:响应对象setHeader(”location”,”/xxx.html”)
* 2)设置状态码:302 进一步请求
*/
/* response.setHeader("location","/hello.html");
response.setStatus(302);*/
//简写方式
response.sendRedirect("/hello.html");
System.out.println("页面跳转了。。。");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
}
当执行tomcat的时候,我们跳转到这个url回车后会立即跳转到hello.html这个页面(hello.html是我们webapp下的一个html文件),这就是重定向;
[外链图片转存失败(img-M8nRJ1LG-1563255979292)(C:\Users\Laptop\AppData\Local\Temp\1561548217262.png)]
将上面的过程可以简化为这样一个流程:
[外链图片转存失败(img-IHMsxnYm-1563255979293)(C:\Users\Laptop\AppData\Local\Temp\1561548268864.png)]
重定向:
请求转发:
实现请求转发的代码示例:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//请求转发原理:
//1)获取全局管理对象
//2)获取请求分发对象:public RequestDispatcher getRequestDispatcher(String path)
//将请求转发到服务器的另一个资源
//3)public void forward(ServletRequest request, ServletResponse response) throws ServletException,
/*ServletContext context = this.getServletContext();
RequestDispatcher rd = context.getRequestDispatcher("/adv.html");
rd.forward(request,response);*/
//简写方式
request.getRequestDispatcher("/adv.html"). //adv.html是当前工程下的一个html广告页面
forward(request,response);
}
特点:一次请求中包含了所有的请求数据
牵扯:请求头 (格式是—— key:value ,在浏览器中F12然后点network可查看当前所有的请求头)
特点:所有的响应数据都在该对象中
牵扯:响应头
重定向的原理就是:location响应头+302状态 (⭐)