Servlet: Servlet Applet 用Java编写的服务器端程序,主要功能在于 交互式地浏览和修改数据,生成动态Web内容
是服务端运行 Java 的小程序起到一个桥梁作用, 用于 服务器 与 浏览器 之间进行沟通
常见的服务器:
- tomcat ( Apache 组织的) 免费
- jetty ( eclipse ) 免费
- (jboss) 收费
- weblogic ( oracle) 收费
- websphere (IBM) 收费
最常用的服务器 Tomcat
Apache Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,能够作为Servlet的运行环境(容器)。它除了能够运行Java Servlet以外,还可以支持JavaServer Pages, Java Expression Language 和 Java WebSocket 技术
在 IDEA 上配置 Tomcat 服务器
1:从官网上下载 tomcat 的 压缩包,下好后直接解压
解压后 tomcat 的目录:
- |-bin /* 可执行脚本目录 */
- |-conf /* 配置文件目录 */
- |-logs /* 日志目录 */
- |-temp /* 临时目录 */
- |-webapps /* 应用程序目录 */ 用于手动添加项目
- |-work /* 工作目录 */
2: 启动 tomcat 服务器
运行前需要配置JAVA_HOME
环境变量,然后到 bin
目录下运行startup.bat
脚本即可启动服务器 启动时要注意观察黑窗口日志,看是否成功。一旦有错误,进入logs
目录查看日志以进一步排查错误起因
成功后,可以访问 http://localhost:8080 能看到Tomcat的Logo页面。
3: 停止服务
可以执行bin
目录下shutdown.bat
,或者使用Ctrl+C
关闭黑窗口
4:打开 IDEA 开始配置 tomcat ,新建一个 java Enterprise 项目 点击 Web Applicaton
5: 点击Run/Debug Configuration
菜单:
按图中步骤依次选择Defaults
,Tomcat Server(Local)
,Configuration
,Tomcat Home
在Tomcat Home
中选中Tomcat的解压目录即可
6: 再点击左上角+
号添加本项目的Tomcat 运行配置即可:
以后用Shift+Alt+F10
弹出菜单中选择要运行配置即可
创建第一个 Web 项目
1: 新建一个 web application
2: 编写第一个 Servlet
/**
* 1. 继承 HttpServlet父类
* 2. 使用注解 @WebServlet(urlPatterns = "浏览器访问路径")
* 3. 覆盖父类中 service 方法
*/
// 注意:在一个项目内,多个servlet的urlPatterns不能重复,要确保唯一
@WebServlet(urlPatterns = "/hello")
public class MyServlet extends HttpServlet {
@Override
// Request : 代表请求
// Response : 代表响应
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("你好,世界");
// 用servlet可以返回一段html代码,给浏览器
// 对于中文,需要设置响应采用utf-8字符集,否则会使用英文字符集(iso-8859-1)返回响应,会有乱码问题
resp.setContentType("text/html;charset=utf-8");
// 向resp对象对象的字符输出流中写入的html代码都会返回给浏览器
resp.getWriter().println("<html><body>你好,世界</body></html>");
}
}
3:写好代码后,通过Shift+Alt+F10
弹出菜单启动tomcat,在浏览器地址栏输入http://localhost:8080/s1
浏览器发送请求:
格式: http://ip地址:端口号/servlet地址?参数名1=参数值1&参数名2=参数值2...
服务器获取请求参数:
String 请求参数的值 = request.getParameter("请求参数名");
****注意:
req.getParameter()
方法的返回值均为字符串类型,所以像age这样的参数需要在servlet中手动转换数据类型- 如果某个请求参数不存在,则
req.getParameter()
返回为null
浏览器发送请求的两种类型: Post 和 Get 两种方式
Get : 直接通过浏览器地址发送请求,希望从服务器获取资源,一般对应查询操作
Post: 向服务器提交新的内容,一般对应新增或修改操作 from表单即可用 Get 提交数据,也可用 Post 提交数据
****Post 和 Get 的区别:
1) get请求会把所有请求参数跟在地址栏之后,不适合发送敏感信息
而post请求不会把请求参数跟在地址栏之后
2) 不要以为post请求是安全的,通过一些网络监测工具仍然可以看到post中的参数信息
http 是不安全的,都是明文发送给服务器的
https 是安全的,会把信息发送给服务器的过程中进行加密
https 和post结合可以保证向服务器传输数据的安全性
3) get请求传输的数据有限制, post请求没有限制(任意大小的数据都可以发送给服务器)
4) get 意味着获取信息(对应查询操作)
post 意味着增,改,删等操作
乱码问题:
对于post请求,会有中文乱码问题,解决方法是调用:
// 手工进行解码, 需要放在所有 req.getParameter方法之前调用
req.setCharacterEncoding("utf-8");
> 注意: tomcat 8 已经对get请求中的中文按utf-8进行解码了, 所以不需要对get请求的中文进行额外处理
tomcat 7, tomcat 6 ... 对get请求中的中文还需要特殊处理
Servlet 的生命周期: 实例化 --》 初始化 --》 服务 --》销毁
浏览器首次向此servlet发送请求时,会创建它的实例对象;以后再发送请求使用的仍然是第一次创建的对象。
***** 结论:整个生命周期中,servlet只有一个实例(单例的)
1) 构造方法首先执行(只执行一次)
2) 初始化方法init (只执行一次)
3) 服务方法 service (反复被执行)来一次请求执行一次
4) 销毁方法 destroy (只执行一次)在服务器停止前,或重新部署时
/**
* servlet 的生命周期
浏览器首次向此servlet发送请求时,会创建它的实例对象;以后再发送请求使用的仍然是第一次创建的对象。
***** 结论:整个生命周期中,servlet只有一个实例(单例的)
1) 构造方法首先执行(只执行一次)
2) 初始化方法init (只执行一次)
3) 服务方法 service (反复被执行)来一次请求执行一次
4) 销毁方法 destroy (只执行一次)在服务器停止前,或重新部署时
*/
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;
//注解
@WebServlet(urlPatterns = "/demo1")
public class ServletDemo1 extends HttpServlet {
//构造方法
public ServletDemo1(){
System.out.println("构造方法只执行一次(在浏览器访问时执行)");
}
//初始化方法(重写父类的初始化方法)
@Override
public void init() throws ServletException {
System.out.println("初始化Servlet");
}
//重写父类的 service() 方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("执行service方法");
}
//销毁servlet, 只有在 停止服务前 / 重新部署服务 时才调用此方法
@Override
public void destroy() {
System.out.println("销毁servlet");
}
}
如何实现servlet的单线程模式?
默认情况下servlet是可以并发处理请求的。如果多个请求同时访问某个servlet,这时服务器会启动多个线程分别处理这些请求,并调用同一个servlet实例中的service方法,这就要求servlet实现时需要考虑线程安全问题。
由于servlet实例的唯一性,如果在servlet中使用了静态变量或成员变量,那么它们就可能会成为临界资源,多线程下就会有并发问题。
一种较好的解决方法是:servlet中避免使用静态变量和成员变量,只允许使用方法内局部变量。
一种不好的解决方法是:让servlet实现SingleThreadModel 接口,这样做web容器会让servlet中的方法仅能被单线程串行访问,并发性大大降低。不论这种方法的优劣,具体代码是:
public class MyServlet extends HttpServlet implements SingleThreadModel { ... }
doGet() 和 doPost()
覆盖service方法,可以处理所有类型的请求
覆盖doGet方法, 仅能处理get方式的请求
覆盖doPost方法,仅能处理post方式的请求
JSP: Java Server Page 是Servlet技术的延伸,用来更方便地产生html响应
jsp 中有
1. 指令: <%@ 指令名 %>
page指令:主要用来指定页面的编码,是否忽略EL等
<%@ page language="java" pageEncoding="UTF-8"%>
<%@ page contentType="页面的内容类型和编码"
import="要导入的java类"
isELIgnored="是否忽略EL表达式的处理"
errorPage="出现错误时,要跳转的页面"
isErrorPage="用在错误页面上,取值为true是错误页面,这时候才能在页面中使用exception变量" %>
exception只能配合jsp表达式和jsp脚本使用
include指令:用来实现页面的静态包含,重用一些页面上的标签和代码
格式: <%@ include file="另一个jsp页面" %>
<%@ include file="/WEB-INF/common/headeradmin.jsp" %>
taglib指令: 用来导入标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
2. 脚本: <% 可以是任意java代码 %>
例:
<%
List<Integer> list = Arrays.asList(1,2,3,4,5);
for(Integer i: list) {
%>
<%
}
%>
3.声明:<%! 可以是任意java代码 (可以声明变量和方法) 相当于 成员变量 %>
<%! int x = 10; %>
<%! public int add(int a, int b) { retrun a + b; } %>
4. 表达式: <%= 表达式 %>把执行结果显示在页面上
i的值是:<%= i %>
JSP原理: 本质仍然是一个 servlet
1) 当首次访问此jsp时,tomcat会把 jsp 转译为 *.java 的类(间接继承自HttpServlet)
2) 再把 *.java 类编译为 *.class 字节码
3) 把 *.class 加载到虚拟机执行,生命周期类似于servlet的生命周期
//jsp 要工作,也必须编译为java类
// HttpJspBase 又是继承了HttpServlet
public class 类名 extends HttpJspBase{
public int i = 100;
public int sum(int a, int b) {
return a+b;
}
public void _jspService(HttpServletRequest request,
HttpServletResponse response) {
int i = 10;
out.println(i++);
}
}
******注意:
1:
脚本
里可以写各种java代码表达式
只能出现一个变量或表达式,作用是将其运算结果输出至页面表达式
结束不能加;
号2:
声明
中的变量是jsp类中的成员变量,因为servlet本身就是单例的,该变量也相当于全局的,相当于成员变量脚本
中的变量相当于jsp类的service方法中的局部变量,线程安全
EL : Expression Language 用于在 JSP 中 展示结果 的语言
语法: ${ 表达式语言 }
如果要用 EL表达式 显示复杂的内容,需要把内容提前放入`作用域`, EL再从`作用域`中把内容取出来显示
步骤一: 放入 jsp作用域中
pageContext.setAttribute(" 名称 ",Object) ; // 给内容(Object)取一个名称,放入作用域中
步骤二: 通过 EL表达式 取出来
${ pageScope.名称 }
EL表达式可以通过
${对象.属性名} 但这里的属性名,依据是对象的get方法,而不是私有属性名
把get方法中get去掉(或把is方法的is去掉),剩余的单词首字母小写,作为对象的属性名,例如
getName() ==> 对象.name
getUsername() ==> 对象.username
getHelloWorld() ==> 对象.helloWorld
isClose() ==> 对象.close
EL表达式的 11 个 内置对象
<!-- 在el表达式取作用域变量时,不加前缀,先搜索pageScope, 再搜索requestScope, 继续搜索sessionScope, 再搜索applicationScope-->
1) pageScope page作用域 类型是map集合
2) requestScope request作用域 类型是map集合
3) sessionScope 会话作用域 类型是map集合
4) applicationScope 应用作用域 类型是map集合5) param 代表所有请求参数集合 类型是map集合
6) paramValues 代表所有请求参数集合(用来获取多值参数)7) cookie 代表请求中所有的cookie集合 map类型
key是cookie的name, value是cookie对象(name,value)8) header 获取请求头的内容 类型是map集合
key是请求头中key的名称
9) headerValues 获取请求头的内容(用来获取多值)
10) initParam 每个jsp可以配置一个初始化参数
initParam.key
11) pageContext 可以获取JSP九大内置对象,相当于使用该对象调用getxxx()方法, 例如pageContext.getRequest()可以写为${pageContext.request)
JSTL : java standard tag library java 标准标签库
使用前需要导包
格式: <%@ taglib prefix="前缀" uri="标签库唯一标识" %>
前缀 核心标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
JSTL 的核心标签库中常用标签使用:
forEach: 循环遍历集合 , 要遍历的集合 必须使用 ${ 要遍历的集合 } 从作用域获取
<c:forEach items="${ 要遍历的集合 } " var="临时变量名" begin="起始数字" end="结束数字">
${临时变量名}
</c:forEach>
if: 条件判断,用来判断条件成立时,才执行if内部的内容,JSTL中 没有 else 标签配合使用
<c:if test="布尔条件">内容</c:if>
<c:choose> <c:when> <c:otherwise> 用于多条件判断
request.setAttribute("salary", 5000.00);
<c:choose>
<c:when test="${salary < 3000.0">低工资</c:when>
<c:when test="${salary > 8000.0">高工资</c:when>
<c:otherwise>中等工资</c:otherwise>
</c:choose>
set 用来向作用域存储值,例如将name=张三的变量存入request域
<c:set var="name" value="张三" scope="request"/>
out : 用来输出特殊内容 它可以对${}输出的内容进行控制,可以控制是否忽略html代码
<c:out escapeXML="false" value="${作用域变量}"> 不忽略html
<c:out escapeXML="true" value="${作用域变量}"> 忽略html,(当做普通文本)
fmt:formatDate 用来格式化日期
fmt:formatNumber 用来格式化数字
<fmt:formatDate value="日期对象" pattern="日期格式"/>
// 数字格式 `#` 和 `0` 其中0可以用来前置补零或后置补零
<fmt:formatNumber value="数字对象" pattern="数字格式"/>
MVC 思想:
由servlet器查询数据,把数据放入作用域,跳转至jsp视图
jsp视图从作用域中获取数据,并展示
M: model 模型 ===》数据(例如从数据库查询出来的list集合, 里面包含java对象)
V:view 视图 ===》数据的展现形式 (jsp就是一种视图技术)
C:controller 控制器 ===》 把模型和视图联系起来 (servlet 充当控制器作用)
响应状态码:服务器常见的错误类型
500 Internal Server Error 服务器内部错误,由于应用程序自己没有正确处理异常,异常抛给了tomcat,这时就会出现500
404 Not Found 资源未找到错误,发生于要访问的资源不存在(资源可能是servlet, jsp, html)
405 Method Not Allowed 方法不支持,
当没有覆盖doGet但发送了get请求时
当没有覆盖doPost但发送了post请求时
200 OK 表示这次请求正常,没有错误
304 这个文件没有修改,请浏览器使用上一次缓存的文件