编译软件:IntelliJ IDEA 2019.2.4 x64
操作系统:win10 x64 位 家庭版
服务器软件:apache-tomcat-8.5.27
目录
- 一. 什么是Servlet?
- 二. 如何编写第一个servlet程序?
- 三. Servlet的生命周期
- 四. Servlet的技术体系
- 五. web项目中的两个接口
- 5.1 Servletconfig接口
- 5.2 ServletContext接口
- 六. 处理请求和响应的接口
- 6.1 HttpservletRequest接口
- 6.2 HttpservletResponse接口
- 七. 请求和响应乱码的处理
- 7.1 请求乱码
- 7.2 响应乱码
- 八. 案例:连接数据库版的登录注册功能
- 8.1 注册功能
- 8.2 登录功能
- 8.3 实现效果
- 九. 使用Beanutils优化代码
- 十. web项目的路径问题 ★
- 10.1 url(常用)
- 10.2 uri(极少用)
一. 什么是Servlet?
Servlet,英文全称为Server Applet,意为服务器端的一小程序
。它运行在支持Java Servlet规范的Web服务器上。在服务器上部署的众多web应用程序中,无论它是B/S架构,还是C/S架构,它们的基本运行模式如下图所示(以Java程序为例):
如果把上述web应用的运行模式比作是一个正在在营业的餐厅,那Servlet在其中扮演着服务员的角色,客人进店吃饭(客户端发出请求),它负责给客人上菜单,等客人点好菜单,servlet就会通知厨子(web应用)做菜(处理业务),厨子做好菜,就让服务员去上菜(响应)给客人。
总的来说,Servlet就是和客户端进行交互(处理请求和响应)
Servlet通常被用于创建像电子商务网站、社交媒体应用、在线银行网站等类似的Web应用程序。通过使用Servlet,开发人员可以以一种可移植、灵活、高效和可重用的方式构建Web应用程序。
二. 如何编写第一个servlet程序?
步骤:
①创建一个html页面,在上面创建一个超链接(计划访问后台的HelloServlet)
<a href="">访问HelloServlet</a>
②创建HelloServlet
- 新建一个普通类HelloServelet
- HelloServelet实现接口Servlet
- 实现接口中的所有抽象方法
代码演示如下:
import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;
public class HelloServelet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 主要功能:处理客户端的请求和响应
* @param servletRequest 处理请求
* @param servletResponse 处理响应
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("访问了HelloServlet类的service方法.......");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
- 在web.xml中为HelloServlet设置访问路径
代码演示如下:
<!-- HelloServlet的访问路径:/hello -->
<servlet>
<!-- 为Servlet起个名字 -->
<servlet-name>abc</servlet-name>
<!-- Servlet的全类名 -->
<servlet-class>t1.HelloServelet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 要和Servlet中的servlet-name的名字一致 -->
<servlet-name>abc</servlet-name>
<!-- 设置访问路径,注意,必须是/开头 -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
③将设置到的访问路径设置给超链接
<a href="hello">访问HelloServlet</a>
④测试HelloServelt
注意:
网页必须直接在web下(不能放在WEB-INF下)
web.xml中url-pattern的值必须以/开头
- 网页的请求路径,不能以/开头
- 网页不能采用静态的打开方式
请求原理如下所示:
Servlet的对象管理:
-
Servlet的实例对象由Servlet容器(tomcat)负责创建
-
Servlet的方法由容器在特定情况下调用
-
Servlet容器会在web应用卸载时(tomcat停止)销毁Servlet对象的实例
三. Servlet的生命周期
Servlet接口中一共有五个方法,其中有三个和生命周期有(init/service/destroy)的方法。
请求过程:
默认情况下在第一次发出请求时,Servlet容器(tomcat服务器)会创建相应的servlet对象、进行初始化(执行init方法)、执行service方法
第二次以及以后的每一次请求发出,都直接执行service方法
在web应用被卸载(服务器被停止时)的时候,servlet对象会被销毁,销毁之前执行destroy方法
Servlet可以在启动服务器时就创建其对象吗?
可以
方法如下:
在web-xml中当前Servlet的servlet标签内添加标签
//设置自启动
<load-on-startup>l</1oad-on-startup>
代码演示如下:
<!-- 设置自启动,若有多个servlet都设了自启动,根据标签体中的值来判定启动优先级,值越小,优先级越高 -->
<!-- <load-on-startup></load-on-startup>中的标签体为非0的整数 -->
<load-on-startup>1</load-on-startup>
四. Servlet的技术体系
创建Servlet的三种方式:
①实现Servlet接口
重写其五个方法(重点关注的只有一个service),其他四个还必须重写
案例:创建HelloServelet 类实现Servlet 接口
代码演示如下:
import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;
public class HelloServelet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 主要功能:处理客户端的请求和响应
* @param servletRequest 处理请求
* @param servletResponse 处理响应
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("访问了HelloServlet类的service方法.......");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
web-xml创建其访问路径:
<!-- HelloServlet的访问路径:/hello -->
<servlet>
<!-- 为Servlet起个名字 -->
<servlet-name>abc</servlet-name>
<!-- Servlet的全类名 -->
<servlet-class>t1.HelloServelet</servlet-class>
</servlet>
<servlet-mapping>
<!-- 要和Servlet中的servlet-name的名字一致 -->
<servlet-name>abc</servlet-name>
<!-- 设置访问路径,注意,必须是/开头 -->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
②继承GenericServlet
步骤:
- 创建一个类
- 继承一个抽象类(GenericServlet)
- 实现抽象类中的抽象方法
- 在web-xml中配置Servlet的访问路径
注意:
GenericServlet主要的功能是将service以外的四个方法做了实现。我们自己的Servlet只需要实现service方法即可,如果想用其他的四个方法,可以采用重写。
案例:创建MyFirstServlet类继承GenericServlet类
代码演示如下:
public class MyFirstServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("触发了继承GenericServlet类的子类MyFirstServlet类的service方法......");
}
}
web-xm配置其访问路径:
<!-- 设置访问MyFirstServlet的路径:/myfirst -->
<servlet>
<servlet-name>def</servlet-name>
<servlet-class>t1.MyFirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>def</servlet-name>
<url-pattern>/myfirst</url-pattern>
</servlet-mapping>
③继承HttpServlet
步骤:
-
创建一个类
-
继承一个抽象类(HttpServlet)
-
重写两个方法doGet和doPost
-
配置Servlet的访问路径
注意:
HttpServlet主要功能是实现service方法,然后对请求进行分发的操作(不同的请求方式调用不同的方法)。get请求调用doGet方法,post请求调用doPost方法。
案例:创建MyFirstServlet类继承GenericServlet类
代码演示如下:
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class SecondServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("访问了SecondServlet里的doPost方法");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("访问了SecondServlet里的doGet方法");
}
}
web-xm配置其访问路径:
<!-- 设置访问SecondServlet的路径:/second -->
<servlet>
<servlet-name>SecondServlet</servlet-name>
<servlet-class>t1.SecondServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SecondServlet</servlet-name>
<url-pattern>/second</url-pattern>
</servlet-mapping>
五. web项目中的两个接口
5.1 Servletconfig接口
一个Servlet对象对应唯一的一个ServletConfigi配置对象
Servletconfig对象如何获得?
在init方法的形参位置,Servletconfig是在当前Servlet进行初始化的时候,传递给init方法的
主要功能:
-
获取Servlet名称(web.xml中servlet-name的值)
//获取Servlet名称 String servletName = servletConfig.getServletName(); System.out.println("servletName:"+servletName);
-
获取全局上下文(ServletContext)对象
//获取全局上下文对象 ServletContext servletContext = servletConfig.getServletContext(); System.out.println("servletContext:"+servletContext);
-
获取Servlet初始化参数
获取Servlet初始化参数的前提是要有servlet的初始化参数
如何设置servlet的初始化参数?
位置:web.xml的servlet标签内,在子标签1–>之上设置,不然报错
代码演示如下:
<!--设置当前Servlet的初始化参数--> <init-param> <param-name>path</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param>
获取Servlet初始化参数:
//获取web-xml中的servlet标签内的初始化参数<param-name>为path的value值 String path = servletConfig.getInitParameter("path"); System.out.println("path:"+path); //获取HelloServelet内所有初始化参数的<param-name>【key】值 Enumeration<String> initParameterNames = servletConfig.getInitParameterNames(); while (initParameterNames.hasMoreElements()){ System.out.println("initParameterNames.nextElement():"+initParameterNames.nextElement()); }
案例:在HelloServelet类实现上述功能
代码演示如下:
import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;
public class HelloServelet implements Servlet {
public HelloServelet() {
System.out.println("HelloServelet类的构造方法被执行了");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("HelloServelet类的init方法被执行了");
//1.获取的是当前Servlet名称(web.xml中配置servlet-name的值)
String servletName = servletConfig.getServletName();
System.out.println("servletName:"+servletName);
//2.获取全局上下文ServletContext对象
ServletContext servletContext = servletConfig.getServletContext();
System.out.println("servletContext:"+servletContext);
//3.获取Servlet初始化参数
//获取web-xml中的servlet标签内的初始化参数<param-name>为path的value值
String path = servletConfig.getInitParameter("path");
System.out.println("path:"+path);
//获取web-xml中的初始化参数<param-name>为aaa的value值
String aaa = servletConfig.getInitParameter("aaa");
System.out.println("aaa:"+aaa);
//获取HelloServelet内所有初始化参数的<param-name>【key】值
Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
while (initParameterNames.hasMoreElements()){
System.out.println("initParameterNames.nextElement():"+initParameterNames.nextElement());
}
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 主要功能:处理客户端的请求和响应
* @param servletRequest 处理请求
* @param servletResponse 处理响应
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("访问了HelloServlet类的service方法.......");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("HelloServelet类的destroy方法被执行了");
}
}
5.2 ServletContext接口
注意:
- 一个web项目只有一个ServletContext对象,代表当前Web应用
- 所有的Servlet共享同一个ServletContext对象,所以ServletContext对象也被称为 application 对象(Web应用程序对象)
- ServletContext对象是由服务器启动的时候,Tomcat去创建,在项目卸载时(服务器关机时)销毁。
如何获得到ServletContext对象?
-
通过ServletConfig去获得
//使用servletConfig获取全局上下文ServletContext对象 ServletContext servletContext = servletConfig.getServletContext(); System.out.println("servletContext:"+servletContext);
-
通过request去获得
//使用servletRequest获取servletcontext对象(全局上下文对象) ServletContext servletContext = servletRequest.getServletContext(); System.out.println("servletContext:"+servletContext);
主要功能:
-
获取项目的上下文路径(带"/"的项目名)
//1.获取项目的上下文路径(带/的项目名) String contextPath = servletContext.getContextPath(); System.out.println("contextPath:"+contextPath);
-
获取虚拟路径所映射的本地真实路径
用途:上传或下载文件时需要使用
//2.获取虚拟路径所映射的本地真实路径(根据相对路径获得绝对路径) String realPath = servletContext.getRealPath("/upload"); System.out.println("realPath:"+realPath);
-
获取WEB应用程序的全局初始化参数
获取全局初始化参数的前提是你得有全局初始化参数,没有的话就得设置
如何设置全局初始化参数?
位置:web.xml 的根节点上
web.xml上的相应代码如下所示:
<context-param> <param-name>context-key</param-name> <param-value>context-value</param-value> </context-param> <context-param> <param-name>ccc</param-name> <param-value>ddd</param-value> </context-param>
//3.获取WEB应用程序的全局初始化参数 //获取全局初始化参数中<param-name>【 key】为ccc的value值 String ccc = servletContext.getInitParameter("ccc"); System.out.println("ccc="+ccc); //获取全局初始化参数中<param-name>【 context-key】为ccc的value值 String context_key = servletContext.getInitParameter("context-key"); System.out.println("context_key="+context_key); //获取全局初始化参数中所有的<param-name>【 key】值 Enumeration<String> initParameterNames = servletContext.getInitParameterNames(); while (initParameterNames.hasMoreElements()){ System.out.println("nextElement:"+initParameterNames.nextElement()); }
-
作为域对象共享数据 ★
域对象:在一定的作用域范围内共享数据的对象
ServletContext所用域范围是整个web项目
测试:
1.在一个Servlet内,往ServletContext对象中设置共享数据
2.在另外一个Servlet内获取到共享的数据
方法:
servletcontext.setAttribute(string key,object obj); object msg servletcontext.getAttribute(string key); //移除指定的共享数据(指定key,删除对应的value) servletcontext.removeAttribute(Sstring key);
案例:尝试使用SecondServlet删除myFirstServlet新建的共享数据test,test的value值自定义
代码演示如下:
//MyFirstServle新增共享数据test并显示 import javax.servlet.*; import java.io.IOException; public class MyFirstServlet extends GenericServlet { @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("触发了继承GenericServlet类的子类MyFirstServlet类的service方法......"); //如何在servletContext作用域范围内添加共享数据 ServletContext servletContext = servletRequest.getServletContext(); servletContext.setAttribute("msg","这是MyFirstServlet设置的共享数据"); //MyFirstServle新增共享数据test并显示 servletContext.setAttribute("test","这是MyFirstServlet设置的test共享数据"); System.out.println("test="+servletContext.getAttribute("test")); } }
//SecondServlet尝试删除并显示MyFirstServlet设置的共享数据test import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class SecondServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("访问了SecondServlet里的doPost方法"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("访问了SecondServlet里的doGet方法"); //如何获取MyFirstServlet在servletContext作用域范围内设置的共享数据 ServletContext servletContext = request.getServletContext(); Object msg = servletContext.getAttribute("msg"); System.out.println("msg="+msg); //删除MyFirstServlet设置的共享数据test servletContext.removeAttribute("test"); System.out.println("SecondServlet已经删除了共享数据test"); System.out.println("共享数据test="+servletContext.getAttribute("test")); } }
六. 处理请求和响应的接口
6.1 HttpservletRequest接口
简介:
该接口是ServletRequest接口的子接口,封装了HTTP请求的相关信息(请求报文中的所有信息都被封装在里面)
主要功能:
-
获得请求头信息
request.getHeader(String key);
//获取请求头中客户端的产品信息 String header = request.getHeader("User-Agent"); System.out.println("客户端的产品信息如下"); System.out.println("header:"+header); //获取请求头中请求来源 String referer = request.getHeader("Referer"); System.out.println("请求来源如下"); System.out.println("referer:"+referer);
-
获得url的路径信息
request.getContextPath()//获取上下文路径 request.getServerName() //获取主机名 request.getServerPort() //获取端口号
//获取url String contextPath = request.getContextPath();//获取上下文路径 System.out.println("contextPath:"+contextPath); //获取主机名 String serverName = request.getServerName(); System.out.println("serverName:"+serverName); //获取端口号 int serverPort = request.getServerPort(); System.out.println("serverPort:"+serverPort);
-
获得请求参数 ★
请求参数是什么?
请求参数就是浏览器向服务器提交的数据。浏览器向服务器如何发送数据?
① 附在url后面(和get请求一致,拼接的形式就行请求数据的绑定),如下下所示:
http://localhost:8989/MyServlet/MyHttpServlet?userId=20&username=jack
② 通过表单提交
<form action="MyHttpServlet" method="post"> 你喜欢的足球队<br /><br /> 巴西<input type="checkbox" name="soccerTeam" value="Brazil" /> 德国<input type="checkbox" name="soccerTeam" value="German" /> 荷兰<input type="checkbox" name="soccerTeam" value="Holland" /> <input type="submit" value="提交" /> </form>
使用HttpServletRequest对象获取请求参数
string request.getparameter(string key); string[] request.getparametervalues("hobby");
//获取请求参数 //根据表单的name值获取它的value值 String username = request.getParameter("username");//获取表单中name为username的value值,下同 System.out.println("username="+username); String password = request.getParameter("password"); System.out.println("password="+password); String gender = request.getParameter("gender"); System.out.println("gender="+gender); //如何根据一个name获取有多个并存的value值 String[] hobbies = request.getParameterValues("hobby"); System.out.println("hobbies:"); for (String hobby : hobbies) { System.out.println(hobby); }
-
获取请求方式
request.getMethod()
//获取请求方式 String method = request.getMethod(); System.out.println("请求方式:"); System.out.println("method:"+method);
-
转发并共享数据
转发是进行页面跳转的主要手段之一
什么是转发?如下图所示
应用场景如下:
a. 转发到第二个servlet
//HttpServletRequest对象reg转发客户端请求至register_error的servlet中 req.getRequestDispatcher("register_error").forward(req,resp);
b. 转发到一个网页
//HttpServletRequest对象reg转发客户端请求至网页register_error中 req.getRequestDispatcher("regist_error.html").forward(req,resp);
使用步骤:
a.获得转发器对象
RequestDispatcher requestDispatcher=request.getRequestDispatcher(目标路径);
b.进行转发操作(将request和response需要传递过去)
requestDispatcher.forward(request,response);
进行页面跳转的代码:
//跳转至root.html request.getRequestDispatcher("root.html").forward(request,response);
Secondservlet能否获得到请求中的请求参数?
可以的,因为转发将request对象传递过去了
request可以作为域对象共享数据(请求域)
应用域(ServletContext):
数据共享范围是整个web应用
请求域(HttpServletRequest)
:数据共享的范围是本次请求,当响应结束了,请求也结束//添加共享数据 setAttribute(string key,object value); //获取共享数据 getAttribute(string key) //移除共享数据 removeAttribute(string kev)
6.2 HttpservletResponse接口
简介:
- 该接口是ServletResponse接口的子接口,封装了服务器针对于HTTP响应的相关信息。(暂时只有服务器的配置信息,没有具体的和响应体相关的内容)
- 由Servlet容器创建其实现类对象,并传入service(HttpServletRequest req, HttpServletResponse res)方法中。
- HttpServletResponse对象指的是容器提供的HttpServletResponse实现类对象。
主要功能:
a.通过输出流将响应数据输出给客户端
Printwriter writer=response.getwriter();
writer.write("<h1>success</h1>");
b.可以设置响应的乱码(添加响应头的方式)
response.addHeader("Content-Type","text/html;charset=utf-8");
简写:response.setContentType("text/html;charset=utf-8");
c.重定向
页面跳转的主要手段之一
什么是重定向?如下图所示:
应用场景如下:
①重定向至另一个Servlet
response.sendRedirect("second");
②重定向至页面
response.sendRedirect("admin.html");
当发送到firstservlet请求中的请求参数,Secondservlet是否能获取到?
取不到;因为发送了第二次请求(第一次请求中的请求参数和第二次请求毫无关系)
重定向能否使用请求域共享数据?
不可以
转发和重定向的区别
转发 | 重定向 | |
---|---|---|
浏览器的感知 | 感知不到 | 感知到 |
网址栏里的网址 | 不变 | 会改变 |
请求的次数 | 一次请求 | 两次请求 |
请求域中的共享数据 | 可以访问 | 不可以访问 |
发起者 | request | response |
WEB-INF | 可以访问 | 不可以访问 |
目标资源 | 本服务器的资源 | 其他服务器的资源 |
ps:
WEB-INF下的资源有一个特性:客户端是访问不到的,但是服务器可以访问,可以把不想让客户端直接访问的资源,放在WEB-INF下
七. 请求和响应乱码的处理
7.1 请求乱码
①
get请求
:tomcat8已经处理好了
注意:
若你的Tomcat版本为7及以下,就需要修改tomcat的配置文件。在server.xml文件修改Connector标签,添加URIEncoding="utf-8"属性,如下图所示:
②
post请求
:中文乱码问题
解决方案:
在代码中获取请求参数之前,设置字符集
代码如下:
request.setcharacterEncoding("utf-8");
案例:form表单以post方式向FirstServlet提交数据,演示post乱码问题
代码演示如下:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class FirstServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//请求
//post方法的中文乱码问题
// request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
System.out.println("username="+username);
String password = request.getParameter("password");
System.out.println("password="+password);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("触发了FirstServlet的doGet方法.......");
/* //设置请求域的共享数据
//注意,设置的共享数据需要放在使用请求转发的代码之前,不然另一个servlet无法获取之前设的请求域共享数据
request.setAttribute("requestMsg","这是requestMsg共享的数据");
request.setAttribute("msg","这是msg");
//实现转发跳转至secondservlet
// request.getRequestDispatcher("second").forward(request,response);
//实现重定向至secondservlet
response.sendRedirect("second");
*/
}
}
添加字符集后修改如下:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class FirstServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//请求
//post方法的中文乱码问题
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
System.out.println("username="+username);
String password = request.getParameter("password");
System.out.println("password="+password);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("触发了FirstServlet的doGet方法.......");
/* //设置请求域的共享数据
//注意,设置的共享数据需要放在使用请求转发的代码之前,不然另一个servlet无法获取之前设的请求域共享数据
request.setAttribute("requestMsg","这是requestMsg共享的数据");
request.setAttribute("msg","这是msg");
//实现转发跳转至secondservlet
// request.getRequestDispatcher("second").forward(request,response);
//实现重定向至secondservlet
response.sendRedirect("second");
*/
}
}
7.2 响应乱码
分类:
①获得输出流直接写数据
写法如下:
response.addHeader("Content-Type","text/html;charset=utf-8);
//简写
response.setContentType("text/html;charset=utf-8");
不信?请看如下演示:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ResponseServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//添加响应头以规避中文乱码
// response.setContentType("text/html;charset=utf-8");
//输出响应数据流给客户端
PrintWriter writer = response.getWriter();
writer.print("<html>");
writer.print("<head>");
writer.print("</head>");
writer.print("<body>");
writer.print("<h1>success 成功</h1>");
writer.print("</body>");
writer.print("</html>");
}
}
代码整体不变,仅添加一句代码如下所示:
//添加响应头以规避中文乱码
response.setContentType("text/html;charset=utf-8");
//输出响应数据流给客户端
PrintWriter writer = response.getWriter();
②转发
③重定向
八. 案例:连接数据库版的登录注册功能
案例:实现登录注册功能,要和数据库比对
8.1 注册功能
步骤:
①搭建环境
-
导入jar包(数据库驱动包、数据库连接池、DBUtils),放在WEB-INF下的lib目录下
-
创建]DBCTools和BaseDao
-
数据库连接池的配置文件(放到src目录下)
-
在MySQL中创建users表格
-
创建实体类(User)
②编写注册功能
- 创建注册页面
- 创建UsersDAOlmpl
- 创建Registe’rServlet
这里提供部分代码:
package DAO;
import bean.users;
import java.sql.SQLException;
public class UsersDAOlmpl extends BaseDAOImpl implements UsersDAO {
@Override
public users findUserByUsername(String username) {
String sql="select * from users where username=?";
try {
return getBean(users.class, sql, username);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public boolean addUser(users user) {
String sql="insert into users values(null,?,?,?)";
try {
int len = update(sql, user.getUsername(), user.getPassword(), user.getEmail());
if (len>0){
return true;
}
return false;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
package DAO;
import bean.users;
public interface UsersDAO {
//注册
//根据用户名来查找相应的用户信息
users findUserByUsername(String username); //登录
//添加用户
boolean addUser(users user);
}
8.2 登录功能
步骤:
- 创建登录页面
- 创建UsersDAOlmpl
- 创建LoginServlet
8.3 实现效果
①测试注册功能
②测试登录功能
九. 使用Beanutils优化代码
简介:
Beanutils是一个Java库,提供了一组实用类,用于处理JavaBeans。JavaBeans是遵循特定约定的Java类,例如具有默认构造函数和用于其属性的getter和setter方法。Beanutils提供了在JavaBeans之间复制属性、将属性值转换为字符串以及执行其他与JavaBeans相关的常见任务的方法。 它是Apache Commons项目的一部分,被广泛用于Java应用程序中。
功能:
自动将map集合中的数据映射到javaBean内
使用条件:
Map集合中的key值必须和javaBean中的属性名一致,不然不一致的那个key值映射不进去
使用步骤:
-
导入jar包
①复制下面的三个jar包,然后粘贴至要应用的本地动态web项目中Web/WEB-INF/lib下
②在lib目录中选中刚才的三个jar包,右击打开–> Add as Library --> Create Library里选相应的参数
-
直接使用Beanutils调用方法即可
案例如下:对上述连接数据库版的登录注册功能的案例中的注册功能使用Beanutils进行优化
代码演示如下:
import DAO.UsersDAOlmpl;
import bean.users;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class RegistServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//处理注册业务
/* String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
//数据库中user表的uid字段是自增长列
users user=new users(null,username,password,email);*/
//使用BeanUtils,减少代码冗余,这样即使注册表单中有300个name属性值,我也不用一个个手动输入,然后再一一添加进user对象里,那样代码量太大
Map<String, String[]> parameterMap = req.getParameterMap();//map集合中的key值是表单中的name属性值
users user=new users();
try {
BeanUtils.populate(user,parameterMap);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
UsersDAOlmpl dao=new UsersDAOlmpl();
users userByUsername = dao.findUserByUsername(user.getUsername());
if (userByUsername==null){
dao.addUser(user);
req.getRequestDispatcher("regist_success.html").forward(req,resp);
}else {
req.getRequestDispatcher("regist_error.html").forward(req,resp);
}
}
}
十. web项目的路径问题 ★
10.1 url(常用)
释义:
统一资源定位符(从整个网络环境中找一个资源),例如http://localhost:9999/day06_servlet_war_exploded/login.html
相对路径
:相对于ur1去作为参照物
绝对路径
:url就是绝对路径(从ip地址开始)
涉及到路径的位置有:
-
网页中的超链接、表单、link、img、script…
-
转发
-
重定向
-
web.xml
注意:
在web项目内,路径前添加/,采用的是绝对路径
建议使用绝对路径,因为绝对路径一旦写死,不管该资源上有多少个上级目录,依然可以找到,若用相对路径,则要时刻注意该资源的上级目录的变化
/代表什么含义?
-
服务器解析
从当前项目下开始找 例如http://localhost:9999/day06_servlet_war_exploded/
①web.xml
例如:
<!-- 设置访问loginservlet的路径 /login --> <servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>t1.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/login</url-pattern> </servlet-mapping>
上述样例设置LoginServlet的访问路径是直接从项目下访问login
<!-- 设置访问loginservlet的路径 /abc/login --> <servlet> <servlet-name>loginServlet</servlet-name> <servlet-class>t1.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>loginServlet</servlet-name> <url-pattern>/abc/login</url-pattern> </servlet-mapping>
上述样例设置Loginservlet的访问路径是从项目下要先找到abc,然后从abc下找login就能找到LoginServlet
②转发
例如://建议使用绝对路径 request.getRequestDispatcher("/second").forward(request,response); //http://localhost:9999/day06_servlet_war_exploded/second
-
浏览器解析
从当前服务器下去找 例如:在 http://localhost:9999/ 下去找
①网页内所有的路径(超链接、表单、link、img、script…)
②重定向
代码举例如下:
response.sendRedirect("second");//不加/,默认前面是./second //重定向是在浏览器里解析,它是从当前服务器下去找,即http://localhost:9999/second去找,绝对找不到,遂报404 /* 解决方案:在second前面加上/day06_servlet_war_exploded/,这样就是在当前项目下去找second,一定能找到 即从http://localhost:9999/day06_servlet_war_exploded/second去找 但是这样写有一个弊端,若修改了上下文路径,代码里也得改,比较麻烦,扩展性不是很好 推荐这样写,即动态的获取上下文路径+/second response.sendRedirect(request.getContextPath()+"/second"); */
总结:
路径前加/,就是使用绝对路径 /的含义,由服务器解析就是当前项目下,由浏览器解析就是当前服务器下,网页内和重定向路径的/由浏览器解析。转发和web.ml中的/由服务器解析
10.2 uri(极少用)
释义:
统一资源标识符(从当前项目下找一个资源)
例如
/day06_servlet_war_exploded/login.html
在名为day06_servlet_war_exploded的war包(在服务器上部署的web项目)下去找login.html