第三次总结
Servlet入门
HTTP响应中有HTML等数据,请求中有什么?
HTTP协议有许多方法,最常用的是GET与POST
GET请求:请求的数据将直接放在URL后明文传输,以
?
分隔,各参数之间以&
分隔POST请求:将数据放在
"消息体"
或者"负载"
中,这个消息体可以非常大
当请求到来时,需要有人来实例化Servlet,有人来调用Servlet的doPost()或doGet()方法,以及重要的参数——HTTP请求和HTTP响应对象.这个人就是Web容器
.
servlet没有main()方法,它们受控于另一个Java应用,即容器,如Tomcat.Web服务器应用(如Apache)得到一个指向servlet的请求,服务器并不是把这个请求交给servlet本身,而是交给部署该servlet的容器,由容器向servlet提供HTTP请求和响应,且由容器调用servlet的方法.
具体过程:
用户点击一个链接,指向一个servlet ==> 容器创建两个对象:HttpServletResponse
和HttpServletRequest
==> 容器根据请求中的URL找到servlet,为这个请求创建或分配一个线程,并把请求和响应对象传递给这个进程(init()
方法被调用,可以覆盖,如获取数据库连接) ==> 容器调用servlet的service()
方法,根据请求的不同类型,service()方法会调用doGet()
或doPost()
方法, doGet()
或doPost()
方法作相应的处理(Servlet的一生主要都在这里度过) ==> 线程结束,容器把响应对象转换为HTTP响应,发回给用户,然后删除请求和响应对象(destroy()
方法被调用)
Servlet中有什么?
1 | import javax.servlet.annotation.WebServlet; |
这里没有service()方法,是因为service()方法是从javax.servlet.http.HttpServlet中继承来的
Get请求是幂等的,而Post请求不是.即重复的Post请求可能会造成不好的后果,如购物结算时重复提交post会购买两次.而Get请求重复提交不会产生副作用,因此需要设计代码以应对重复提交Post请求
从请求中获取参数:
获取单个参数对应的单个值:
1 | request.getParameter() //返回值为一个值 |
获取像复选框这样的一个参数对应多个值:
1 | request.getParameterValues() //返回值为一个数组 |
向响应中传输数据:
大多数情况下使用响应是为了向客户发回数据.会对响应调用两个方法:setContentType()
和getWriter()
.在此之后,只需要完成I/O将html或者其他内容写到流中.比如向客户发送一个JAR:
1 | package servlet.DownloadServlet; |
response.setContentType("application/jar");
这一行是告诉浏览器你要发回什么,这样浏览器才能有正确的处理.常用的MIME类型:
- text/html
- application/pdf
- video/quicktime
- application/java
- image/jpeg
- application/jar
- application/octet-stream
- application/x-zip
更多见:MIME 参考手册
对于输出,有两个选择:
字符
或者字节
ServletReponse接口只提供了两个可以选择的流:
- ServletOutputStream用于输出字节
- PrintWriter用于输出字符数据
PrintWriter:
1
2PrintWriter writer = response.getWriter();
whiter.println("some text and html");用于将文本数据打印到字符流,专门用来处理字符数据
OutputStream:
1
2ServletOutputStream out = response.getOutputStream();
out.write(aByteArray);用于写其他的所有内容
PrintWriter实际上包装了ServletOutputStream.但是PrintWriter会装饰这个流使其对字符支持更好
事实上可以直接写一个指向JAR的链接,这样就无需经过servlet.但是如果需要执行更多的代码,比如判断该用户是否有权下载这个JAR,就需要经过servlet来判断.
Redis基本操作
下载安装包:
1 | wget http://download.redis.io/releases/redis-5.0.5.tar.gz |
解压:
1 | tar -zcvf redis-5.0.5.tar.gz |
编译:
1 | cd redis-5.0.5.tar.gz |
安装到指定目录:
1 | make install PREFIX=/usr/local/redis |
将redis.conf
文件复制到/usr/local/
中:
1 | cp redis.conf /user/local |
配置redis.conf
:
1 | vim redis.conf |
基本配置主要修改三处,其保持默认即可使用:
daemonize no
改为daemonize yes
,以守护进程方式运行- 将
bind:127.0.0.1
这一句注释掉 - 找到
requirepass
,将这一句取消注释,并修改为自己的密码,即requirepass 你的密码
运行服务端:
1 | cd /usr/local/redis |
查看服务端运行状态:
1 | ps aux|grep redis |
基本操作
1 | redis-cli --raw |
Maven入门
1. 检查JDK安装
在安装Maven之前,首先要确认安装了JDK.
2. 下载Maven
点击下载apache-maven-3.6.1-bin.zip,解压文件到指定目录,设置环境变量
3. Maven使用入门
3.1 编写pom.xml
Maven的核心文件是pom.xml.POM(Project Object Model)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖等等.
以下为一个pom.xml:
1 |
|
第一行是XML头,指定该XML文档的版本和编码方式.
紧接着是project元素,是所有pom.xml的根元素,声明一些POM相关的命名空间和xsd元素,不是必须的,但是能够让第三方工具帮助我们快速编辑POM.
根元素下的第一个子元素modelVersion指定了当前POM模型的版本,对于Maven2和Maven3,只能是4.0.0
最重要的是包含groupId、artifactId和version的三行.这三个元素定义了一个项目基本的坐标.
- groupId:定义项目属于哪个组,这个组往往和项目所在的组织或公司存在关联.如果你的公司是mycom,有一个项目是myapp,那么groupId就应该是com.mycom.myapp
- artifactId:定义当前Maven项目在组中唯一的ID.在myapp中可能为不同的子项目(模块)分配不artifactId,如myapp-util,myapp-web等
- version:定义当前项目的版本.
- name:声明了一个对用户更为友好的项目名称,虽然不是必须的,但是推荐使用以方便交流
添加依赖:
<dependencies>
元素中可以包含多个<dependency>
元素以声明项目的依赖.通过groupId,artifactId,version定位一个jar,Maven将从中央仓库下载.JUnit依赖中的<scope>
表示依赖范围,如果依赖范围为test,则表示该依赖只对测试有效.如果不声明依赖范围,默认值为compile,表示对主代码和测试代码都有效.
3.2 打包和运行
pom中没有指定打包类型,则使用默认打包类型jar.
1 | mvn clean package |
执行该命令后,将获得项目的jar包,可以将该jar包复制到其他项目的Classpath中以使用该jar包.
但是如何让其他的Maven项目引用这个jar呢?
需要一个安装的步骤:
1 | mvn clean install |
此时这个jar包被安装到了本地Maven仓库中.
但是生成的jar包不是可执行的,为了生成可执行的jar包,需要借助maven-shade-plugin
,将该插件添加到pom.xml中:
1 | <plugin> |
然后执行mvn clean install
,构建完成后打开target/目录,生成两个jar包,其中original开头的为原始的jar包,另一个为可执行的jar包,执行该jar包:
1 | java -jar target ***.jar |
3.3 使用Archetype生成项目骨架
手动创建Maven的目录非常麻烦,可以使用maven archetype生成项目的骨架:
如果是Maven 3:
1 | mvn archetype:generate |
如果是Maven 2:
1 | mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-5:generate |
4. 项目坐标详解
Maven为各种构件引入了秩序,任何一个构件都必须明确定义其坐标,一组Maven坐标通过一些元素定义,分别是:groupId
,artifactId
,version
,packaging
,classifier
.
- groupId:定义当前Maven项目隶属的实际项目,一般为域名反向对应.注意要定义到项目级别而不应该只定义到组织级别.如
com.sonatype.nexus
,而不是com.sonatype
- artifactId:定义实际项目中的一个Maven项目(模块),使用实际项目名称作为其前缀,如
nexus-indexer
,使用实际项目名nexus作为前缀.这样的好处是方便寻找构件. - version:定义Maven项目当前所处的版本.版本管理后面介绍.
- packaging:定义Maven的打包方式,默认值为jar
- artifactId:用来帮助定义构建输出的一些附属构件.不能直接定义项目的classifier,因为附属构件不是项目直接默认生成的,而是由附加的插件帮助生成.
以上五个元素,groupId,artifactId,version为必须定义的,packaging为可选的,classifier是不可直接定义的
5. 依赖的配置
1 | <dependencies> |
- groupId,artifactId,artifactId:基本坐标
- type:依赖的类型,对应于项目坐标定义的packaging,大部分情况下该元素不必声明,其默认值为jar
- scope:依赖的范围
- optional:标记依赖是否可选
- exclusions:用来排除传递性依赖
大部分依赖声明只包含基本坐标,在一些特殊情况下,其他元素至关重要.对其他元素将在后面的文章介绍