Servlet
概述
全程Server Applet,即java编写的服务器端程序,该程序运行在服务器中,主要负责客户端与servlet通信与调用servlet方法
作用:
1.接收用户的请求数据
2.调用其他的java程序,处理请求数据
3.根据处理的结果来将结果响应给客户端
Servlet的创建与使用
流程:
1.创建一个用于处理前端请求的servlet类继承javax.servlet.http包下的HttpServlet类
该类的规范编写是在项目的servlet目录下创建,类名由自定义名称+Servlet构成,例如处理登录请求的servlet类可以命名为LoginServlet
2.重写父类中的init,service,destroy方法
//1.继承HttpServlet类
public class LoginServlet extends HttpServlet {
//2.重写service(),init(),destroy()方法
public LoginServlet(){
System.out.println("LoginServlet的无参构造");
}
//创建servlet对象,会将配置信息作为参数传入
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("LoginServlet的init()方法");
//通过getInitParameter方法获取web.xml中的配置信息
System.out.println("init:"+config.getInitParameter("n"));
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("LoginServlet的service()方法");
System.out.println(req);
System.out.println(resp);
}
@Override
public void destroy() {
System.out.println("LoginServlet的destroy()方法");
}
}
3.在Web.xml文件中进行配置
Web.xml文件是web应用的配置文件用于对web资源进行配置,该文件位于WEB-INF目录下服务器在启动时会读取web.xml文件中的内容。
配置需要两步:
①注册项目中的servlet
<servlet>
<servlet-name>自定义的对象名</servlet-name>
<servlet-class>servlet的全类名</servlet-class>
</servlet>
<!--
< servlet>元素用于注册Servlet,它包含有两个主要的子元素:
< servlet-name>和< servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
-->
②为servlet配置地址
<servlet-mapping>
<servlet-name>对应注册的对象名</servlet-name>
<url-pattern>/Login</url-pattern><!--对应的url地址-->
</servlet-mapping>
<!--
< servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:
< servlet-name>和< url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。
-->
由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用< servlet>元素和< servlet-mapping>元素完成
Servlet中的四个方法
无参的构造方法
servlet类中无参构造方法用于初始化类的成员,在客户端第一次发送请求或者在服务器启动时,tomact会创建servlet对象,此时会调用无参的构造方法,默认情况下都是在第一次请求发送后才创建servlet对象,若是在Web.xml文件的< servlet>元素中配置
<load-on-startup>-1</load-on-startup>
大于等于0代表servlet对象在服务器启动时创建(满加载),小于0代表对象在发送请求时创建
init
该方法在无参的构造方法后调用,用于初始化servlet,只会调用一次
与无参的构造方法一样有两种情况调用
该方法会传入一个ServletConfig参数,这是一个接口,由tomcat提供实现类并且用于封装servlet对象的信息
可以在Web.xml的< servlet>元素中配置
<init-param>
<param-name>n</param-name>
<param-value>jim</param-value>
</init-param>
此时利用ServletConfig的对象调用getInitParameter(String name)方法即可获取该配置信息的值
service
该方法为前端提供服务,每次请求时都会调用该方法
该方法的两个参数HttpServletRequest与HttpServletResponse ,这也是java中的两个接口,由tomcat提供实现类
destroy
该方法在服务器关闭时调用,主要用于执行servlet程序的最终操作例如存储数据,打印日志等,只会调用一次
上述三个方法的调用顺序是无参构造-->init-->service-->destroy,构造方法在最前面调用,而后面三个方法的调用顺序是由顶层的Servlet接口中的规定的,所有该接口的实现类都需要遵循该规定
前后端程序的交互
Servlet的生命周期
实例化:无参构造方法 --> 初始化:init--> 服务:service --> 销毁:destroy
web项目的重新编译
在后端的java代码中如果改变了servlet的类名或者改变了配置文件,导致项目无法正常运行则需要重新将java文件重新编译并且重新部署到tomcat上
编译后的java文件放在out目录下的artifacts目录下,如果需要重新编译则需要工具栏中的build选项中的build artifacts菜单项,选择Clean可以清空目录下被编译过的java文件,然后再重新选择Rebuild即可重新编译
最后将原tomcat中的项目去除,再重新将java项目部署到tomcat服务器上即可
Http协议
在前端向后端发送请求时,会遵循Http协议
概述
● 超文本传输协议,服务器传输超文本到本地浏览器的协议用于定义客户端浏览器和服务器之间交换数据的过程。
● HTTP是一个基于TCP/IP通信协议来传递数据
● HTTP是一个属于应用层的协议
http请求
客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个http请求
例如:点击超链接,提交表单,都是在向后端发送一个http请求
请求包括:
请求行:包括请求的地址,请求方式,请求的状态,请求资源名称,http版本
请求头:包含服务器端的信息,以及客户端的一些环境信息,以键值对的形式传递
请求体:存储post请求的数据,请求体中参数以键值形式传递,多个用&链接,服务器接收到后再解析.
请求方式
GET方式:
超链接访问,默认是GET方式 form提交,不指定method,默认为GET方式 POST方式: form提交,指定method=“POST” Get方式与post方式的区别 Get方式主要是从服务器获取信息;post主要是向服务器提交信息 Get方式在通过URL提交数据,数据在URL中可以看到;POST方式,数据放置在请求体中提交。 GET方式提交的数据大小受限制一般1kb(不同浏览器也会有不同);而POST则没有此限制。
doGet()与doPost()方法
servlet中针对两种请求方式分别有两个方法来应对,分别是doGet()与doPost()方法,该方法中在service方法中调用.
在Servlet的搭建过程中需要新建一个Servlet类继承自HttpServlet类,这个步骤就导致了该子类一定会满足Servlet接口中规定的规范即便不重写init,servic,destroy方法,在客户端向服务器端发送请求的时候还是会按规范调用这几个方法。所以要在doGet()与doPost()方法中实现对http请求的响应可以直接在servlet中单独重写这两个方法
HttpServletRequest对象:(接收请求的数据)
tomcat服务器会将http请求的所有数据都封装到HttpServletRequest接口的实现类的对象中去,在数据处理的过程中使用该对象就可以获取请求的信息
获取请求头:getHeader(String name)
获取传输的数据: String getParameter(String name) String getParameterValues(String name)
在Tomcat8之后的版本中get请求的数据可以自动转码,但是post请求的数据需要在接收之前设置解码的规则
req.setCharacterEncoding("utf-8")
//1.继承HttpServlet类
public class LoginServlet_back extends HttpServlet {
//2.重写service(),init(),destroy()方法
/* public LoginServlet_back(){
System.out.println("LoginServlet的无参构造");
}
//创建servlet对象,会将配置信息作为参数传入
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("LoginServlet的init()方法");
//通过getInitParameter方法获取web.xml中的配置信息
System.out.println("init:"+config.getInitParameter("n"));
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("LoginServlet的service()方法");
System.out.println(req);
System.out.println(resp);
}
@Override
public void destroy() {
System.out.println("LoginServlet的destroy()方法");
}
*/
/*
get与post方法是在service中调用的方法,在前端发送请求后会在service方法中判断请求的方式然后再进行方法的调用
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req.getMethod());
System.out.println(req.getProtocol());
System.out.println(req.getRequestURL());
System.out.println(req.getHeader("User-Agent"));
System.out.println(req.getParameter("name"));
System.out.println(req.getParameter("age"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//接收数据
req.setCharacterEncoding("utf-8");
System.out.println(req.getMethod());
System.out.println(req.getProtocol());
System.out.println(req.getRequestURL());
System.out.println(req.getHeader("User-Agent"));
System.out.println(req.getParameter("account"));
System.out.println(req.getParameter("password"));
System.out.println(req.getParameter("gender"));
String []hobbys=req.getParameterValues("hobby");
System.out.println(Arrays.toString(hobbys));
//处理数据
//响应
resp.setContentType("text/html;charset=utf-8");//设置响应的字符集
PrintWriter printWriter= resp.getWriter();
printWriter.print("提交成功");
}
}public class LoginServlet extends HttpServlet {
/*
get与post方法是在service中调用的方法,在前端发送请求后会在service方法中判断请求的方式然后再进行方法的调用
*/
/* @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req.getMethod());
System.out.println(req.getProtocol());
System.out.println(req.getRequestURL());
System.out.println(req.getHeader("User-Agent"));
System.out.println(req.getParameter("name"));
System.out.println(req.getParameter("age"));
}
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");//设置响应的字符集
PrintWriter printWriter= resp.getWriter();
String token = req.getHeader("token");
DecodedJWT dec = JWTUtil.getTokenInfo(token);
int id = dec.getClaim("id").asInt();//获取token中的id
String account = dec.getClaim("account").asString();//获取token中的账号信息
System.out.println("id :" + id + " account :" + account);
CommandResult commandResult = new CommandResult(200,null,"验证token成功");
printWriter.print(new ObjectMapper().writeValueAsString(commandResult));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");//设置响应的字符集
PrintWriter printWriter= resp.getWriter();
CommandResult commandResult=null;
//处理数据
try {
LoginDao loginDao=new LoginDao();
Admin admin=loginDao.checkAccount(req.getParameter("account"),req.getParameter("password"));
if (admin!=null){
String token = JWTUtil.token(admin.getId(),admin.getAccount());
admin.setToken(token);
commandResult=new CommandResult(200,admin,"登录成功");
}else{
commandResult=new CommandResult(201,null,"账号或密码错误");
}
} catch (Exception e) {
commandResult=new CommandResult(500,null,"服务器忙,请稍后再试");
}
printWriter.print(new ObjectMapper().writeValueAsString(commandResult));
}
}
http响应
一个http响应代表服务器向客户端回送的数据,它包括:响应行,响应头,响应体。
响应行:里包含了http协议版本,以及用于描述服务器对请求的处理结果。 HTTP/1.1 (协议版本) 200(状态吗) OK(状态码描述) 状态码:服务器和浏览器用于确定状态的固定数字号码 200:请求成功 302:请求重定向 400:语义有误,当前请求无法被服务器理解或请求参数有误 404:请求资源不存在,通常是路径写错了或者服务器资源删除了 500:服务内部错误(代码异常)
响应头:用于描述服务器的基本信息,以及数据描述 Server Apache-Coyote/1.1 Content-Type text/html;charset=UTF-8 Content-Length 0 Date Wed, 13 Sep 2017 02:26:07 GMT
响应体:代表服务器向客户端浏览器回送的正文
HttpServletResponse对象:(封装响应的数据)
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个代表响应的HttpServletResponse对象。服务器端向客户端返回的数据都会封装在该对象中
该对象的常用方法:
getWriter(),获得一个PrintWriter字符输出流输出数据,用于向前端响应数据,设置响应体中的数据
PrintWriter打印流(向前端响应数据):
print(String message), write(String message) 两种方式都可以向前端打印字符串
response会默认以ISO8859-1将需要输出到浏览器的字符进行解码,如果输出的字符在ISO8859-1中不存在,就会导致乱码问题。
response.setContetnType("text/html;charset=utf-8");方法可以同时设定response所使用的字符集编码和浏览器打开所用的字符集编码。
过滤器
Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源(可以拦截接收与响应的web资源):例如Servlet, 从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
作用:对服务器web资源进行拦截(权限控制,通过拦截资源进行权限控制,是否可以访问)
Filter接口
Servlet中提供了一个接口Filter类,实现了该接口的类被称为过滤器Filter,通过该类即可实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截.
Servlet接口中规定的规范要求要执行三个方法
init(FilterConfig filterConfig):该方法是对filter对象进行初始化的方法,仅在容器初始化filter对象结束后被调用一次。参数FilterConfig可以获得filter的初始化参数。
doFilter(ServletRequest request, ServletResponse response,FilterChain chain):该方法是filter进行过滤操作的方法,是最重要的方法。过滤器实现类必须实现该方法。方法体中可以对request和response进行预处理。其中FilterChain可以将处理后的request和response对象传递到过滤链上的下一个资源。
destroy():该方法在容器销毁过滤器对象前被调用。
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("编码过滤器");
servletRequest.setCharacterEncoding("utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
}
配置过滤器
filter过滤器开发好了之后,需要在web.xml文件中配置该过滤器
<!--注册项目中的过滤器-->
<filter>
<filter-name>encode</filter-name><!--过滤器的名称-->
<filter-class>com.yzl.webback.filter.EncodingFilter</filter-class><!--由反射机制创建对象-->
</filter>
<!--配置进入过滤器的地址-->
<filter-mapping>
<filter-name>encode</filter-name><!--与注册过滤器的名称对应-->
<url-pattern>/*</url-pattern><!--设置哪些请求servlet的资源-->
</filter-mapping>