什么是Maven
- Maven是java世界中常用的构建工具
- 一个程序在编写时往往要涉及到第三方库多的一些依赖,另外还需要争对这个写好的程序打包部署
- Maven存在的意义就是为了方便的进行依赖管理和打包
- 除了Maven还有一些别的构建工具比如Maven后一个选项Gradle,不过Gradle在安卓后端开发比较用的多,java后端用的比较少
- Maven类似于python中的pip
- python中的anaconda不是这种构建工具,anaconda是python把一些机器学习相关的库打包到一起了,机器学习的库,广泛用到c++,直接使用pip安装会调用你本地的c++环境对库的代码进行编译(不过你电脑的c++环境不一定能编译出来,linux的c++环境更容易部署),而anaconda是大佬给你下载打包好了,你直接用就好
1.0 创建Maven项目
IDEA选择Maven构建
目录介绍
Src(放置源代码文件)
main文件夹 放置业务代码
- main文件下 java文件夹 放置java文件
- mian文件夹下的resources文件夹放置一些依赖的资源(比如图片,音频)
test文件夹 放置测试代码
- test文件夹 放置测试代码
pom.xml
- 是maven项目的主要配置文件,maven主要用来管理依赖和打包
- groupId artifactId version 者几个键值对,如果你要把你写的程序放到maven的中央仓库的时候,我们才需他要通过这几个属性做区分,groupId是公司或者组织,artifactId是产品名称,version是版本号,这三个联合到一起为库的区分标签
- properties 是配置属性,比如是java的版本和生成程序的java版本和字符集编码信息等
2.0 引入依赖
概念
- Maven 项目创建完毕后, 会自动生成一个 pom.xml 文件.
- 我们需要在 pom.xml 中引入 Servlet API 依赖的 jar 包.
- 我们当前的代码要使用servlet开发,而servlet并不是java标准库自带的,因此我们要让maven能够把servlet的依赖给获取了
- 先找到 maven 的中央仓库,通过中央仓库就可以找到想获取的依赖
下载过程
- 在中央仓库 https://mvnrepository.com/ 中搜索 “servlet”, 一般第一个结果就是.
- 选择3.1.0版本 Maven Repository: javax.servlet » javax.servlet-api » 3.1.0 (mvnrepository.com)
- Servlet的版本和Tomcat的版本是有对应关系的,Tomcat使用8 Servlet就是3.1,如果不匹配就可能出现问题
- 把坐标复制
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
- 在xml中创建
<dependencies></dependencies>
标签,然后把上诉的内容复制过去 ,<dependencies></dependencies>
标签 ( 标签内部放置项目依赖的 jar 包. maven 会自动下载依赖到本地. )
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
3.0 手动创建目录
概念
- tomcat对servlet项目是有一些额外的要求的
- Maven是一个通用的工具,可以管理的不仅仅是servlet的项目,还可以管理别的
- 在这个基础上,再按照servlet项目的要求创建出特定的目录和文件
过程
- 在main文件下,创建目录webapp
- 在webapp目录下创建WEB-INF文件目录
- 在WEB-INF中创建一个web.xml文件,web.xml就是告诉tomcat我这个目录里面的东西就是一个webapp,你就要把我加载起来
- 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>
</web-app>
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >
是schema文件,描述了xml文件里面的格式是怎么样的(哪些标签是合法的,哪些不合法,如何进行嵌套),IDEA拿到这些文件,就可以争对你的xml代码进行补全了
存在问题
如果下载很久不行或者报错(网络相关的错误,比如访问某个地址超时)
- 可以手动修改maven源,比如国内的阿里云源获取数据,默认maven源是国外的服务器
4.0 编写代码
在 java 目录中创建一个类 HelloServlet, 代码如下:
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//这个注解,就把当前这个servlet类和一个请求的路径关联起来了
//也叫(配置路由),tomcat会在合适的时机自动调用doGet,
// 1)看请求的方法:只有GET请求才能调用doGet,如果是POST会调用doPost,PUT则对应toPUT
// 2)看请求的路径,看url后面那个带有层次结构䣌路径,一个servlet程序可能有多个servelt类,这些servelt类需要在不同情况下执行到,我们希望这个servelt类根hello这个路径相关
// 当我们请求的路径中带有hello的时候,才会执行到我们这个helloservelt的代码,不同的Servlet类就饿可以关联不同的路径
@WebServlet("/hello")
//这里继承HttpServlet,是前面Servlet的jar包提供多个类
//编写Servlet程序一般都要继承这个类
public class HelloServlet extends HttpServlet {
//重写父类方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//req代表http的请求内容
//resp代表这次请求要返回的http内容
//doGet这个方法本质也是一个"回调函数",把这个方法写好之后交给Tomcat
//Tomcat在收到一个合适的GET请求后就会自动调用doGet,
//在调用doGet的时候,Tomcat就会解析这一次的HTTP请求,生成一个HttpServletRequest对象(这个对象里面的属性都是和HTTP协议格式匹配的)
//Tomcat同时会构造出一个空的HttpServletResponse对象,这里的空指的是new好的但是没初始化属性的对象,把这个HttpServletRequest对象也传给doGet里面
//doGet 要做的事情就是根据这次请求(req),计算出响应(resp)
//doGet里面的代码,就要根据req里不同的参数细节,生成一个具体的resp对象(往空对象里面设置属性)
//Tomcat就会根据这个响应对象,转换成符合http协议的响应报文,然后返回给浏览器
//此时打印在服务器日志中产生(tomcat的日志中)
System.out.println("hello servlet2222");
//返回"hello servlet2222"给用用户
//通过getWriter()获取resp对象内部封装的输出流对象,就是字符流(对标字节流)
//然后用write方法,就可以把一个字符串写到resp对象中(具体就是写到了http响应的body中)
//浏览器拿到响应中的body就可以显示到界面上
resp.getWriter().write("hello servlet222");
}
}
- 创建一个类 HelloServlet , 继承自 HttpServlet
- 在这个类上方加上
@WebServlet("/hello")
注解, 表示 Tomcat 收到的请求中, 路径为/hello
的请求才会调用 HelloServlet 这个类的代码. (这个路径未包含 Context Path) - 重写
doGet
方法.doGet
的参数有两个, 分别表示收到的 HTTP 请求 和要构造的 HTTP 响应. 这个 方法会在 Tomcat 收到 GET 请求时触发 HttpServletRequest
表示 HTTP 请求. Tomcat 按照 HTTP 请求的格式把 字符串 格式的请求转成 了一个HttpServletRequest
对象. 后续想获取请求中的信息(方法, url, header, body 等) 都是通 过这个对象来获取.HttpServletResponse
表示 HTTP 响应. 代码中把响应对象构造好(构造响应的状态码, header, body 等)resp.getWriter()
会获取到一个流对象, 通过这个流对象就可以写入一些数据, 写入的数据会被 构造成一个 HTTP 响应的 body 部分, Tomcat 会把整个响应转成字符串, 通过 socket 写回给浏览 器- 前面写的echo server的时候,一个服务器,典型工作流程就是三部:
- 读取请求并解析—相对固定(tomcat帮你完成)
- 根据请求计算响应—体现服务器业务逻辑
- 把响应写回到客户端–相对固定(tomcat帮你完成)
- servlet 程序不需要main方法,程序是需要main方法做为人口,实际上,我们要写的代码,并不是独立的程序,而是放到tomcat上执行的,main方法在tomcat上,写的这个doGet是让tomcat来调用
5.0 打包程序
程序要放到Tomcat上运行,就需要对于程序进行打包
打成一个Tomcta能识别的包的格式,此时代码才会被Tomcat给加载起来
打包借助maven来完成
打jar包步骤
- 打开 maven 窗口 (一般在 IDEA 右侧就可以看到 Maven 窗口, 如果看不到的话, 可以通过 菜单 -> View -> Tool Window -> Maven 打开)
- 然后展开 Lifecycle , 双击 package 即可进行打包.
- 如果比较顺利的话, 能够看到 SUCCESS 这样的字样.
- 如果代码/配置/环境存在问题, 可能会提示 BUILD FAILED, 可以根据具体提示的错误信息具体解决.
- 打包成功后, 可以看到在 target 目录下, 生成了一个 jar 包
- 这样的 jar 包并不是我们需要的, Tomcat 需要识别的是另外一种 war 包格式.
- 另外这个 jar 包的名字太复杂了, 我们也希望这个名字能更简单一点.
war 包和 jar 包的区别
- jar 包是普通的 java 程序打包的结果. 里面会包含一些 .class 文件
- war 包是 java web 的程序, 里面除了会包含 .class 文件之外, 还会包含 HTML, CSS, JavaScript, 图 片, 以及其他的 jar 包. 打成 war 包格式才能被 Tomcat 识别
- 两者本质没啥区别,不过war包会包含一些简单的前端代码(html css js),以及一些tomcat的配置文件(web.xml)
打war包步骤
- 在 pom.xml 中新增一个 packing 标签, 表示打包的方式是打一个 war 包.
<packaging>war</packaging>
- 在 pom.xml 中再新增一个 build 标签, 内置一个 finalName 标签, 表示打出的 war 包的名字是
HelloServlet
<build>
<finalName>ServletHelloWorld</finalName>
</build>
- 完整的 pom.xml 形如
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>servlet</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<packaging>war</packaging>
<build>
<finalName>serveltHelloword</finalName>
</build>
</project>
- 重新使用 maven 打包, 可以看到生成的新的 war 包的结果.
6. 部署程序
把 war 包拷贝到 Tomcat 的 webapps 目录下.
启动 Tomcat/或者tomcat本身就在运行 , Tomcat 就会自动把 war 包解压缩成一个目录.
7. 验证程序
-
通过浏览器发起一个http GET请求来触发servlet的代码
-
此时通过浏览器访问
http://127.0.0.1:8080/ServletHelloWorld/hello
-
通过第一级路径
/ServletHelloWorld
确定war包解压的文件,从而确定一个webapp -
通过第二级路径确定哪个servlet
-
通过方法,来确定执行servlet中的哪个方法
-
总结:URL 中的 PATH 分成两个部分, 其中 HelloServlet 为 Context Path, hello 为 Servlet Path
更方便的部署方式
-
手动拷贝 war 包到 Tomcat 的过程比较麻烦. 我们还有更方便的办法
-
此处我们使用 IDEA 中的 Smart Tomcat 插件完成这个工作
-
“插件” 即 (plugin)
安装 Smart Tomcat 插件
- 菜单 -> 文件 -> Settings
- 选择 Plugins, 选择 Marketplace, 搜索 “tomcat”, 点击 “Install”.
- 安装完毕之后, 会提示 "重启 IDEA
配置 Smart Tomcat 插件
- 点击右上角的 “Add Configuration”
- 选择左侧的 “Smart Tomcat”
- .在 Name 这一栏填写一个名字(可以随便写)
- 在 Tomcat Server 这一栏选择 Tomcat 所在的目录. 其他的选项不必做出修改
其中 Context Path 默认填写的值是项目名称
这会影响到后面咱们的访问页面.
- 点击 OK 之后, 右上角变成了
- 点击绿色的三角号, IDEA 就会自动进行编译, 部署, 启动 Tomcat 的过程.
此时 Tomcat 日志就会输出在 IDEA 的控制台中, 可以看到现在就不再乱码了.(在windows上部署)
- 端口号不需要与tomcat里的conf中的server.xml里的端口一致,著需要保证后续你浏览器发的HTTP请求的端口号与你smart cat里的端口号一致就可以了
存在问题
- 如果第一次启动报错address already in use 则表示你原来启动的tomcat已经开启了,tomcat只能开一个,所以把原来的关了,在idea再打开即可
http://127.0.0.1:8080/win_1/hello
此时就可以访问了127.0.0.1是环回ip
Smart Tomcat工作原理
- 不是把你的webapp拷贝到webapps目录下
- 而是会创建另一个目录(临时目录),会让Tomcat加载这个临时目录中的webapp
- 对于老版本的插件来说,我们可通过日志看到临时目录的位置,且是不可变的
- 新版本,这个路径可以配置的
- 这个临时的路径默认是
C:\Users\Ap0stoL2\.SmartTomcat\servlet\servlet