Tomcat是一个HTTP服务器,在TCP服务器的基础上加了一些额外的功能,能够解析请求中的HTTP报文,把请求转换成结构化数据(对象),也能很方便的构造HTTP响应。HTTP服务器提供了一组API,方便程序员直接调用来操作HTTP协议,从而简化程序员的开发工程。servlet程序是一个war后缀的文件,tomcat会自动把war解压缩得到一个目录,每个war其实就对应了一个webapp,一个Tomcat可以部署多个servlet程序,所以可以把Tomcat称为“servlet的容器”。
maven是java世界中非常知名的“工程管理工具”/“构建工具”,核心功能:管理依赖,构建/编译,打包。maven存在的意义就是能够直接把这些操作串起来,一气呵成。
完成一个servlet的hello world
1.创建一个maven项目
2.引入依赖
需要在代码中引入servlet api,这个api不是jdk内住的,而是第三方tomcat提供的,借助Maven直接引入。
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 Applicationdisplay-name>
web-app>
5.打包和部署
使用smart tomcat插件
可以这样认为:
一个Tomcat上可以同时部署多个网站,一个网站上又有多个页面,一个请求中的第一级路径用于告诉tomcat要访问的网站是哪个,第二级路径告诉tomcat要访问的页面是这个网站的那个页面。
啥时候浏览器发的是GET请求?
啥时候浏览器发送的是POST请求?
1)让Tomcat先从指定的目录中找到所有要加载的Servlet类
前面部署的时候是把Servlet代码编译成了.class,然后打包成了war包。然后拷贝到了webapps里面。Tomcat就会从webapps里来找到哪些.class对应的Servlet类,并进行加载。
2)根据刚才类加载的结果,给这些类创建Servlet实例
3)实例创建好之后,就可以调用当前Servlet实例的init方法了
4)创建TCP socket,监听8080端口,等待有客户端来连接
5)如果循环退出了,Tomcat也要结束了就会一次循环调用每个Servlet的destroy方法
1)req司通过读取socket中的数据,然后爱按照HTTP协议的请求格式来解析的,构造成了一个HttpServletRequest对象,resq这里则是相当于new了一个空对象
2)判定当前要的顶球是否是静态文件,如果是静态文件就要读取文件内容,把文件内容够遭到resq对象的body中,并且返回这个resq对象
3)根据请求的URL来获取到使用哪个类来处理
URL里有两个路径。
第一级路径:Context Path,确定一个webapp
第二级路径:Servlet path,确定一个Servlet类
如果没有找到匹配的Servlet类就会返回404
4)根据刚才找到的Servlet对象,来调用service方法,在service方法内部又会进一步调用doGet/doPost,下面是service方法内部
我们写的代码就是通过继承这个类,重写其中的方法来被Tomcat执行
展示请求的响应
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("首行部分
");
stringBuilder.append(req.getProtocol());
stringBuilder.append("
");
stringBuilder.append(req.getMethod());
stringBuilder.append("
");
stringBuilder.append(req.getRequestURI());
stringBuilder.append("
");
stringBuilder.append(req.getContextPath());
stringBuilder.append("
");
stringBuilder.append(req.getQueryString());
stringBuilder.append("
");
stringBuilder.append("header部分
");
Enumeration<String> headerNames = req.getHeaderNames();
while(headerNames.hasMoreElements()){
String headerName = headerNames.nextElement();
String headerValue = req.getHeader(headerName);
stringBuilder.append(headerName + ":" + headerValue + "
");
}
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write(stringBuilder.toString());
}
}
展示参数的请求
@WebServlet("/getParameter")
public class getParameter extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userId = req.getParameter("userId");
String classId = req.getParameter("classId");
resp.getWriter().write("userId=" + userId + "classId=" + classId);
}
}
1.x-www-form-urlencoded
获取参数的方式和GET一样,也是getParameter
在前端构造一个这样格式的请求
1)form表单
userId=1234&classId=5678
<form action="postGetParameter" method="post">
<input type="text" name="userId">
<input type="text" name="classId">
<input type="submit" value="提交">
form>
3)json
可以使用第三方的库来直接处理json格式数据,主要使用的库叫做Jackson,通过maven把jackson这个库下载到本地并引入到项目中。
在浏览器前端代码中通过js构造json格式的请求
在java后端代码中通过jackson来进行出,需要使用jackson把请求body中的数据读取出来并解析成Java中的对象。
class User{
public int userId;
public int classId;
}
@WebServlet("/postJson")
public class PostJsonServlet extends HttpServlet {
//1.创建一个Json的核心对象
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//2.读取body中的请求,然后使用ObjectMapper来解析成需要的对象
//readValue就是把Json格式的字符串转成Java的对象
//第一个参数表示对那个字符串进行转换,这个参数可以填成一个String,也可以填成一个InputStream对象,还可以填一个File
//第二个参数表示要把这个JSON格式的字符串转成哪个Java对象
User user = objectMapper.readValue(req.getInputStream(), User.class);
resp.getWriter().write("userId=" + user.userId + ",classId:" + user.classId);
}
}
点击提交之后在浏览器控制台中就打印出来了服务器的响应数据,当前使用的是ajax的方式来提交数据,这个操作默认不会产生页面跳转,就和使用form风格差别很大。
例子1:
服务器返回状态码
@WebServlet("/status")
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(200);
resp.getWriter().write("hello");
}
}
例子2:
实现自动刷新这样的页面效果,给HTTP响应中设置一个header:Refresh即可
@WebServlet("/autoRefresh")
public class AutoRefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Refresh", "1");
resp.getWriter().write("timestamp:" + System.currentTimeMillis());
}
}
例子3:
构造一个重定向,构造一个302
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(302);
resp.setHeader("Location", "https://www.sogou.com");
}
}
Servlet提供的关键API
HttpSession getSession():在服务器中获取会话,参数如果为true,则当不存在会话时创建会话;参数如果为false,则当不存在会话时返回null
Cookie[] getCookies():返回一个数组,包含客户端发送该请求的所有Cookie对象,会自动把Cookie中的东西解析成键值对。每个Cookie对象又包含了两个属性name和value
在调用getSession的时候具体要做的事情:
1.创建会话
首先现获取请求中cookie里面的sessionId字段(相当于会话的身份标识),判定这个sessionId是否存在当前服务器上存在,如果不存在则进入创建会话逻辑。创建会话,会创建一个HttpSession对象,并且生成一个sessionId(是一个很长的数字,通常是用16进制来表示,能够保证唯一性),接下来就会把这个seesionId作为key,把这个HttpSession对象作为value,把这个键值对给保存到服务器内存的一个“哈希表”这样的结构中。再然后服务器就会返回一个HTTP响应,把sessionId通过Set-Cookie字段返回给浏览器,浏览器就可以保存这个sessionId到cookie中了。
2.获取会话
先获取到请求中的cookie里面的sessionId字段,判定这个sessionId是否存在当前服务器上存在,如果有就直接查询出这个HttpSession对象,并且通过返回值返回回去。
HttpSession
这个对象本质上也是一个键值对的结构,允许程序员往HttpSession对象中,存储人的键值对数据,key必须是String,value是一个Object
HttpSession里面的每个键值对称为属性。
HttpSession提供了两个方法:
getAttribute取键值对
setAttribute存键值对
Cookie提供的方法:
String getName():该方法返回cookie的名称,名称在创建后不能改变。
String getValue():该方法获取与cookie关联的值
void setValue(String newValue):该方法设置于cookie关联的值
void addCookie(Cookie cookie):把指定的cookie添加到响应中,响应中就可以根据addCookie这个方法,来添加一个Cookie信息到响应报文中。这里添加进来的键值对就会作为HTTP响应中的Set-Cookie字段来表示。