一、JavaWeb
1、JavaWeb的概念
1)什么是JavaWeb?
JavaWeb是指,所有通过Java语言编写可以通过浏览器访问的程序的总称。
JavaWeb是基于请求和响应来开发的
什么是请求?
是指客户端给服务端发送数据,叫请求Request
什么是响应?
是指服务器给客户端回传的数据,叫响应Response
请求和响应是成对出现的!
2、Web资源的分类
web资源按实现的技术和呈现的效果不同,又分为静态资源和动态资源两种。
静态资源:html、css、js、txt、MP4视频、jpg图片
动态资源:jsp页面、Servlet程序
3、常用的Web服务器
4、Tomact服务器和Servlet版本的对应关系
Servlet程序从2.5版本是现在使用最多的版本(xml配置),到了Servlet3.0之后就是注解版本的Servlet使用。
二、Tomact
5、Tomact的使用
5.1 目录介绍
bin 专门用来存放tomact服务器的可执行程序
conf 专门用来存放tomact服务器的配置文件
lib 专门用来存放tomact服务器的jat包
logs 专门用来存放tomact服务器运行时输出的日记信息
temp 专门用来存放tomcat运行时产生的临时数据
webapps 专门用来存放部署的web工程
work 是tomcat工作时的目录。用来存放tomcat运行时jsp翻译为Servlet的源码。和Session钝化的目录。
5.2 如何启动Tomcat服务器
Tomcat目录下的startup.bat文件,双击。
如何测试Tomcat服务器启动成功
打开浏览器,在浏览器地址栏中输入以下地址测试:
1、http://localhost:8080
2、http://127.0.0.1:8080
3、http://真是ip:8080
常见的启动失败情况:
1、双击startup.bat文件,就会出现一个小黑框一闪而过,失败的原因时因为没有配置好JAVA_HOME环境变量
2、显示中文出现乱码
找到Tomcat目录中conf中的logging.properties文件,
把java.util.logging.ConsoleHandler.encoding = UTF-8修改为java.util.logging.ConsoleHandler.encoding = GBK即可
另一种启动tomcat服务器的方式
① 打开命令行
② cd到tomcat的bin目录下
③ 敲入启动命令: catalina run
5.3 Tomcat的停止
方式① 点击tomcat服务器窗口的x关闭按钮
方式② 把tomcat服务器窗口置为当前窗口,然后按快捷键Ctrl+c
方式③ (主要方式)找到tomcat的bin目录下的shutdown,bat双击,就可以停止tomcat
5.4 如何修改Tomcat的端口号
Mysql默认端口号是:3306
Tomcat默认的端口号是:8080
找到Tomcat目录下的conf目录,找到server.xml配置文件
HTTP协议默认的端口号是:80
5.5 如何部署web工程到Tomcat中
第一种方法:只需要把web工程的目录拷贝到Tomcat的webapps目录下即可。
例如:1、在webapps目录下创建一个book工程:
2、书城内容拷贝到里面
3、如何访问Tomcat下的web工程
例如访问book工程下的网页http://127.0.0.1:8080/book/index.html
第二种方法:需要Tomcat目录中conf目录的Catalina里localhost创建如下的配置文件
<!--Context表示一个工程上下文
path表示工程的访问路径:/abc
docBase表示工程目录在哪里
-->
<Context path="/abc" docBase="D:\JavaWeb\Tomcat\apache-tomcat-10.0.6-windows-x64\apache-tomcat-10.0.6\webapps\book" />
会出现资源打开的错误
<Context path="/abc" docBase="D:\JavaWeb\book" />
更换book的路径就可以正常执行了
http://192.168.163.1:8080/abc/
5.6 手托html页面到浏览器和在浏览器中输入地址访问文件的不同
5.7 ROOT的工程的访问,以及默认index.html页面的访问
当在浏览器地址中输入访问地址如下:
http://ip:port/ 没有工程名的时候,默认访问的是ROOT工程
当在浏览器地址栏中输入的访问地址如下:
http://ip:port/工程名/ 没有资源名,默认访问index,html页面
6、IDEA整合Tomcat服务器
File->Settings->Build,Execution,Deployment->Application Servers
如何创建动态的web工程
1)先创建一个普通的java模块,然后在此模块的根目录右键选中Add Frameworks Support 然后选中Web Application和右边的Create web xml
动态web的目录存放写什么?
7、如何在IDEA中部署工程到Tomcat上运行
1)
2)
3)
4)注意在中间白框左下角“+”号
实现刷新即可看到刚修改的页面内容
三、Servlet
8、Servlet技术
8.1 什么是Servlet
1) Servlet是JavaEE规范之一,规范就是接口
2) Servlet就JavaWeb三大组件之一。三大组件分别是Servlet程序、Filter过滤器、Listener监听器。
3) Servlet是运行在服务器上的一个java小程序,可以接收客户端发送过来的请求,并响应数据给客户端。
8.2 手动实现Servlet程序
1) 编写一个类去实现Servlet接口
2)实现service方法,处理请求,并响应数据
3)到web.xml中去配置servlet程序的访问地址
举例代码如下:
① 实现接口Servlet,并重写方法,service是专门用来处理请求和响应的
public class ServletTest implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/*
* service方法是专门用来处理请求和响应的
* */
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("ServletTest被访问了");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
② web.xml中去配置servlet程序的访问地址
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--servlet标签给Tomact配置Servlet程序-->
<servlet>
<!--servlet-name标签是给Servlet程序起一个别名(一般是类名)-->
<servlet-name>ServletTest</servlet-name>
<!--servlet-class是Servlet程序的全类名-->
<servlet-class>Servlet.ServletTest</servlet-class>
</servlet>
<!--servlet-mapping标签给servlet程序配置访问地址-->
<servlet-mapping>
<!--servlet-name标签作用是告诉服务器,当前配置的地址给哪个Servlet程序使用-->
<servlet-name>ServletTest</servlet-name>
<!-- url-pattern标签配置访问地址
/ 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径
/servlet 表示地址为http://ip:port/工程路径/hello
-->
<url-pattern>/servlet</url-pattern>
</servlet-mapping>
</web-app>
8.3 Servlet的生命周期
1)执行Servlet构造器方法
2)执行init初始化方法
1)、2),是在第一次访问的时候创建Servlet程序会调用
3)执行service方法
3)每次访问都会调用
4)执行destroy销毁方法
4)结束时才会被调用
8.4 Servlet请求的分发处理
1)先创建一个html文件,地址是访问路径,方式是get获取方式。当在浏览器访问html文件后,点击提交就会get到Servlet访问的结果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080//06_servlet_war_exploded/servlet" method="get">
<input type="submit">
</form>
</body>
</html>
2)重写修改实现Servlet接口的ServletTest类的service方法,已知httpServletRequest.getMethod()获取请求的方法,故可以进行判断
/*
* service方法是专门用来处理请求和响应的
* */
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("3 ServletTest被访问了");
//类型转换,因为有getMethod()方法
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
//获取请求的方式
String method = httpServletRequest.getMethod();
if ("GET".equals(method)){
System.out.println("get请求");
}else if ("POST".equals(method)){
System.out.println("post请求");
}
}
8.5 通过继承HttpServlet实现Servlet程序
一般在实际项目开发中,都是使用继承HttpServlet类的方式去实现Servlet程序。
1)编写一个类去继承HttpServlet类
2)根据业务需要重写doGet或doPost方法
3)到web.xml中的配置Servlet程序的访问地址
举例代码如下:
① 继承HttpServlet类,并重写方法doGet和doPost。
public class ServletTest2 extends HttpServlet {
/*
* 在get请求是调用
* */
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ServletTest2 的doGet方法");
}
/*
* 在post请求是调用
* */
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ServletTest2 的doPost方法");
}
}
② web.xml中的配置Servlet程序的访问地址
<!--配置ServletTest2-->
<servlet>
<servlet-name>ServletTest2</servlet-name>
<servlet-class>Servlet.ServletTest2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletTest2</servlet-name>
<url-pattern>/servlet2</url-pattern>
</servlet-mapping>
8.6 使用IDEA创建Servlet程序
首先File->Project Structure中的Facets,然后点击Add Application Sercer specific… 添加后,再在Soure Roots下的列打上对勾,即可在当前项目中new Servlet
以上操作之后,不仅创建了继承HttpServlet类ServletTest3类,并且在web.xml中自动生成了servlet-name标签是给Servlet程序起一个别名(一般是类名)的操作,只需要servlet-mapping标签给servlet程序配置访问地址。
8.6 Servlet类的继承体系
9、ServletConfig类
ServletConfig类从类名上看,就是Servlet程序的配置信息类
Servlet程序和ServletConfig对象都是由Tomcat负责创建,我们负责使用。
Servlet程序默认是第一次访问的时候创建,ServletConfig是每个Servlet程序创建时,就创建一个对应的ServletConfig对象。
9.1 ServletConfig类的三大作用
1)可以获取Servlet程序的别名servlet-name的值
2)获取初始化参数init-param
3)获取ServletContext对象
public class ServletTest implements Servlet {
public ServletTest() {
System.out.println("1 构造器方法");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("2 初始化方法");
// 1)可以获取Servlet程序的别名servlet-name的值
System.out.println("ServletTest程序的别名是:"+servletConfig.getServletName());
// 2)获取初始化参数init-param
System.out.println("初始化参数username的值是:"+servletConfig.getInitParameter("username"));
System.out.println("初始化参数url的值是:"+servletConfig.getInitParameter("url"));
// 3)获取ServletContext对象
System.out.println(servletConfig.getServletContext());
}
......省略其他重写方法
}
要获取初始化参数,需要在web.xml文件中ServletTest的配置添加修改成如下:
<!--配置ServletTest-->
<!--servlet标签给Tomact配置Servlet程序-->
<servlet>
<!--servlet-name标签是给Servlet程序起一个别名(一般是类名)-->
<servlet-name>ServletTest</servlet-name>
<!--servlet-class是Servlet程序的全类名-->
<servlet-class>Servlet.ServletTest</servlet-class>
<!--init-param是初始化参数-->
<init-param>
<!--参数名-->
<param-name>username</param-name>
<!--参数值-->
<param-value>root</param-value>
</init-param>
<init-param>
<!--参数名-->
<param-name>url</param-name>
<!--参数值-->
<param-value>jdbc:mysql://localhost:3306/test</param-value>
</init-param>
</servlet>
<!--servlet-mapping标签给servlet程序配置访问地址-->
<servlet-mapping>
<!--servlet-name标签作用是告诉服务器,当前配置的地址给哪个Servlet程序使用-->
<servlet-name>ServletTest</servlet-name>
<!-- url-pattern标签配置访问地址
/ 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径
/servlet 表示地址为http://ip:port/工程路径/hello
-->
<url-pattern>/servlet</url-pattern>
</servlet-mapping>
10、ServletContext类
10.1 什么是ServletContext?
1)ServletContext是一个接口,它表示Servlet上下文对象
2)一个web工程,只有一个ServletContext对象实例
3)ServletContext对象是一个域对象。
4)ServletContext是在web工程部署启动的时候创建。在web工程停止的时候销毁。 (即当工程一直在部署中的时候,不管在哪里访问ServletContext对象中的数据都是可以访问到,覆盖到整个web工程,类似全局共享)
什么是域对象?这里的域指的是存取数据的操作范围,整个web工程。
域对象,是可以像Map一样存取数据的对象,叫域对象。
存数据 取数据 删除数据
Map put() get() remove()
域对象 setAttribute() getAttribute() removeAttribute()
10.2 ServletContext类的四个作用
1)获取web.xml中配置的上下文参数context-param
2)获取当前的工程路径,格式:/工程路径
3)获取工程部署后在服务器硬盘上的绝对路径
4)像Map一样存取数据
public class ContextServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1)获取web.xml中配置的上下文参数context-param
ServletContext context = getServletConfig().getServletContext();
String username = context.getInitParameter("username");
System.out.println("context-param参数username的值是:"+username);
String password = context.getInitParameter("password");
System.out.println("context-param参数password的值是:"+password);
// 2)获取当前的工程路径,格式:/工程路径
System.out.println("获取当前工程路径:"+context.getContextPath());
// 3)获取工程部署后在服务器硬盘上的绝对路径
// / 斜杠被服务器解析地址为:http://ip:port/工程名
// 06_servlet_war_exploded映射到IDEA代码的当前web目录
System.out.println("工程部署后路径:"+context.getRealPath("/"));
System.out.println("工程下css目录的绝对路径是:"+context.getRealPath("css"));
System.out.println("工程下imgs目录1.jpg的绝对路径是:"+context.getRealPath("/imgs/8.jpg"));
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
要获取参数以及工程路径,需要在web.xml文件中的配置添加修改成如下:
<!--context-param是上下文参数(属于整个web工程)-->
<context-param>
<param-name>username</param-name>
<param-value>context</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>root</param-value>
</context-param>
11、Http协议
11.1 什么是HTTP协议
什么是协议?
协议是指双方,或多方,相互约定好,大家都需要遵守的规则,叫协议。
所谓HTTP协议,就是指,客户端和服务器之间通信时,需要遵守的规则,叫HTTP协议。
HTTP协议中的数据又叫报文。
11.2 请求的HTTP协议格式
客户端给服务器发送数据叫请求;服务器给客户端回传数据叫响应。
请求又分为GET请求和POST请求
1) GET请求
(1) 请求行
① 请求的方式 GET
② 请求的资源路径[+?+请求参数]
③ 请求的协议的版本号 HTTP/1.1
(2)请求头
key:value 组成 不同的键值对,表示不同的含义
2) POST请求
(1) 请求行
① 请求的方式 POST
② 请求的资源路径[+?+请求参数]
③ 请求的协议的版本号 HTTP/1.1
(2)请求头
key:value 组成 不同的键值对,表示不同的含义
空行
(3)请求体 就是发送给服务器的数据(可以是hidden隐藏数据)
3) 常用的请求头的说明
① Accept:表示客户端可以接收的数据类型
② Accept-Languege:表示客户端可以接收的语言类型
③ User-Agent:表示客户端浏览器的信息
④ Host:表示请求时的服务器ip和端口号
4) 哪些是GET请求,哪些是POST请求
GET 用于从指定资源请求数据。
GET请求有哪些?
① form标签 method=get
② a标签
③ link标签引入css
④ Script标签引入js文件
⑤ img标签引入图片
⑥ iframe引入html页面
⑦ 在浏览器地址栏中输入地址后敲回车
POST 用于将数据发送到服务器来创建/更新资源。
POST请求有哪些?
① form标签 method=post
11.3 响应的HTTP协议格式
1)响应
(1)响应行
① 响应的协议和版本号
② 响应状态码
③ 响应状态描述符
(2)响应头
① key:value 不同的响应头,尤其不同的含义
空行
(3)响应体 就是回传给客户端的数据
2)常见的响应码说明
200 表示请求成功
302 表示请求重定向
404 表示服务器已经收到请求。但需要的数据不存在(请求地址错误)
500 表示服务器已经收到请求,但是服务器内部错误(代码错误)
11.4 MIME类型说明
12、HttpServletRequest类
12.1 HttpServletRequest类有什么作用
每次只要有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中。然后传递到service方法(doGet和doPost)中给我们使用。可以通过HttpServletRequest对象,获取到所有请求的信息。
12.2 HttpServletRequest类常用方法
1)获取资源路径、统一资源定位符、ip地址、请求头、请求方式
public class RequestAPIServlet extends HttpServlet {
//HttpServletRequest req是把请求过来的HTTP协议
// 信息解析好封装到Request对象
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取资源的请求路径
System.out.println("URI=>"+req.getRequestURI());
//获取请求的统一资源定位符(绝对路径)
System.out.println("URL=>"+req.getRequestURL());
//获取客户端的ip地址
// //在IDEA中,使用localhost访问时,得到的客户端ip地址是 127.0.0.1
// //在IDEA中,使用127.0.0.1访问时,得到的客户端ip地址是 127.0.0.1
// //在IDEA中,使用真是ip地址访问时,得到的客户端ip地址是 真实ip
System.out.println("客户端 ip地址=>"+req.getRemoteHost());
//获取请求头
System.out.println("请求头User-Agent==>"+req.getHeader("User-Agent"));
//获取请求的方式GET或POST
System.out.println("请求的方式==>"+req.getMethod());
}
}
2)获取请求参数值
注意:有多个值的时候使用getParameterValues方法,返回的是一个String类型的数组
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobbys = req.getParameterValues("hobby");
System.out.println("用户名:"+username);
System.out.println("密码:"+password);
System.out.println("兴趣爱好:"+ Arrays.asList(hobbys));
}
}
12.3 请求转发
什么是请求的转发?(一次请求,分多步完成)
请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发。
浏览器查询地址为:
http://localhost:8080/07_servlet/servlet1?username=aaaa
故Servlet1代码如下:
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求的参数(办事的材料)查看
String username = request.getParameter("username");
System.out.println("在Servlet1(柜台1)中查看参数(材料):"+username);
//给材料盖一个章,并传递到Servlet2(柜台2)去查看
request.setAttribute("key","柜台1的章");
//问路:Servlet2(柜台2)怎么走 Dispatcher调度员的意思
/*
* 请求转发必须要以斜杠大头,/
* 斜杠表示地址为:http://ip:port/工程名/,映射到IDEA代码的web目录
* getRequestDispatcher获取请求转发对象
* */
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
//走向Servlet2(柜台2) forward是走向...的意思
requestDispatcher.forward(request,response);
}
Servlet2代码如下:
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求的参数(办事的材料)查看
String username = request.getParameter("username");
System.out.println("在Servlet2(柜台2)中查看参数(材料):"+username);
//查看柜台1是否有盖章
Object key = request.getAttribute("key");
System.out.println("柜台1是否有盖章:"+key);
//处理自己的业务
System.out.println("Servlet2(柜台2) 处理自己的业务");
}
12.4 base标签的作用
简单的实现一个页面跳转和返回:
注:初始默认访问工程下的index,html文件
但是当采用请求转发来实现的时候就会出现错误 - - -原因是:回跳的路径出现错误
index.html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
这是web下的index.html<br>
<a href="a/b/c.html">a/b/c.html</a>
<a href="http://localhost:8080/07_servlet/forwardC">请求转发:a/b/c.html</a>
</body>
</html>
c.html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
这是a下的b下的c.html文件<br/>
<a href="../../index.html">跳回首页</a>
</body>
</html>
解决请求转发时出现的错误方法是:采用base标签
故对c.html代码改进如下: 回跳时,会先看有没有base值,存在的话,就会忽略转发进来之后的当前路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--base标签设置页面相对工作时参照的地址
href属性就是参数的地址值
-->
<base href="http://localhost:8080/07_servlet/a/b/c.html">
</head>
<body>
这是a下的b下的c.html文件<br/>
<a href="../../index.html">跳回首页</a>
</body>
</html>
12.5 Web中的相对路径和绝对路径
12.6 Web中 / 斜杠的不同意义
13、HttpServletResponse类
13.1 HttpServletResponse类有什么作用
HttpServletResponse类和HttpServletRequest类一样。每次请求进来,Tomcat服务器都会创建一个Resqponse对象传递给Servlet程序去使用。HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息。如果需要设置返回给客户端的信息,都可以通过HttpServletResponse对象来进行设置。
13.2 两个输出流的说明
字节流 getOutputStream(); 常用于下载(常二进制数据)
字符流 getWriter(); 常用于回传字符串(常用)
注意:
两个流同时只能使用一个,使用了字节流,就不能使用字符流,反之亦然。
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter();
response.getOutputStream();
}
以上情况就会报错!!!
13.3 如何往客户端回传数据
要求:往客户端回传字符串数据
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//要求:往客户端回传字符串数据
PrintWriter writer = response.getWriter();
writer.write("response's content!!!");
}
解决响应的中文乱码问题
重要点在于要保持服务器的字符集与浏览器的字符集一致且支持中文显示
方法① 可以知道当前服务器的字符集,然后去修改服务器字符集与浏览器一致
方法② 通过响应头,设置浏览器的字符集与服务器一致。
方法③(推荐) 同时设置服务器和客户端都使用UTF-8字符集,还设置了响应头 - - - 此方法一定要在获取流对象之前调用才有效
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(response.getCharacterEncoding());//服务器默认UTF-8
//可设置服务器字符集为,例如修改为GBK
//response.setCharacterEncoding("GBK"); //因为谷歌浏览器识别的GBK,故可修改为GBK来正常显示
//通过响应头,设置浏览器也使用UTF-8
//response.setHeader("Content-Type","text/html;charset=UTF-8");
//以下代码会同时设置服务器和客户端都使用UTF-8字符集,还设置了响应头
//此方法一定要在获取流对象之前调用才有效
response.setContentType("text/html;charset=UTF-8");
//要求:往客户端回传字符串数据
PrintWriter writer = response.getWriter();
writer.write("真好!!!");
}
13.4 请求重定向
什么是请求重定向?(多次请求,每次请求也可多步,最后才完成)
是指客户端给服务器发请求,然后服务器告诉客户端说。我给你一些地址,你去新地址访问,叫请求重定向(因为之前的地址可能已经被废弃)。
浏览器查询地址为:
http://localhost:8080/07_servlet/response1
故Response1代码如下:- - - 两种方式,推荐 方式二,方式二中302代码已经在其中设置好了。
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("曾到此一游 Response1");
/*//方式一:
//设置响应状态码302,表示重定向(已搬迁)
response.setStatus(302);
//设置响应头,说明新的地址在哪里
response.setHeader("Location","http://localhost:8080/07_servlet/response2");
*/
//方式二(推荐):302代码在其中已经设置好了
response.sendRedirect("http://localhost:8080/07_servlet/response2");
}
Response2代码如下:
public class Response2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("response2's result!");
}
14. 请求转发与重定向的区别
图解如下:
补:
请求转发 请求重定向
浏览器地址栏 不发生变化 发生变化
请求次数 1次 2次或更多次
Request域数据 共享 不共享
WEB-INF下的资源 可以访问 不能访问
工程以外的资源 不能访问 可以访问
15. JavaEE的三层架构
分层的目的是为了解耦,解耦就是为了降低代码的耦合度,方便项目后期的维护和升级。
web层 Servlet/controller
Service层 service Service接口包
service.impl Service接口实现类
dao持久层 dao Dao接口包
dao,impl Dao接口实现类
实体bean对象 pojo/entity/domain/bean JavaBean类
测试包 junit
工具包 utils
16. 书城项目- - - 第二阶段
16.1 先创建书城需要的数据库和表。
```sql
create database book;
use book;
create table t_user(
`id` int primary key auto_increment,
`username` varchar(20) not null unique,
`password` varbinary(32) not null,
`email` varbinary(200)
);
insert into t_user(`username`,`password`,`email`) values('admin','admin','admin@163,com');
select * from t_user;
16.2 编写数据库表对应的JavaBean对象
public class User {
private Integer id;
private String username;
private String password;
private String email;
...
...
}
16.3 编写工具类JdbcUtils
JdbcUtils类代码如下:
public class JdbcUtils {
private static DruidDataSource dataSource;
static {
try {
Properties properties=new Properties();
// 读取jdbc.properties属性配置文件,获取流
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//从流中加载数据
properties.load(inputStream);
//创建数据库连接池
dataSource= (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 获取数据库连接池中的连接
* */
public static Connection getConnection() throws Exception{
DruidPooledConnection conn = dataSource.getConnection();
return conn;
}
/*
* 关闭连接,放回数据库连接池
* */
public static void close(Connection conn){
if (conn!=null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
其中需要读取属性配置文件如下:
username=root
password=4680123
url=jdbc:mysql://localhost:3306/book
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
JdbcUtilsTest测试如下:
public class JdbcUtilsTest {
@Test
public void testJdbcUtils(){
try {
for (int i=0;i<100;i++){
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
JdbcUtils.close(connection);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
16.4 编写BaseDao - - - 对数据库进行增删改查操作
使用导入的DbUtils来操作
public abstract class BaseDao {
//使用DbUtils操作数据库
private QueryRunner queryRunner = new QueryRunner();
/*
* update()方法用来执行:insert、update、delete语句
* 如果返回-1,说明执行失败,返回其他表示影响的行数
* */
public int update(String sql,Object...args){
Connection connection=null;
try {
connection = JdbcUtils.getConnection();
return queryRunner.update(connection,sql,args);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return -1;
}
/*
* 查询返回一个javaBean的sql语句
* */
public <T>T queryForOne(Class<T> type,String sql,Object...args){
Connection connection=null;
try {
connection = JdbcUtils.getConnection();
return queryRunner.query(connection,sql,new BeanHandler<T>(type),args);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
/*
* 查询返回多条javaBean的sql语句
* */
public <T> List<T> queryForList(Class<T> type, String sql, Object...args){
Connection connection=null;
try {
connection = JdbcUtils.getConnection();
return queryRunner.query(connection,sql,new BeanListHandler<T>(type),args);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
/*
* 查询返回一行一列的sql语句的值
* */
public Object queryForList(String sql, Object...args){
Connection connection=null;
try {
connection = JdbcUtils.getConnection();
return queryRunner.query(connection,sql,new ScalarHandler(),args);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
}
16.5 编写UserDao和测试
编写UserDao类
public interface UserDao {
//根据用户名查询用户信息
public User queryUserByUsername(String username);
//保存用户信息
public int saveUser(User user);
//根据用户名和密码查询用户信息
public User queryUserByUsernameAndPassword(String username,String password);
}
编写UserDaoImpl - - -继承BaseDao(具有增删改查操作)、实现UserDao(具有判断方法)
public class UserDaoImpl extends BaseDao implements UserDao {
@Override
public User queryUserByUsername(String username) {
String sql="select `id`,`username`,`password`,`email` from t_user where username=?";
return queryForOne(User.class,sql,username);
}
@Override
public User queryUserByUsernameAndPassword(String username, String password) {
String sql="select `id`,`username`,`password`,`email` from t_user where username=? and password=?";
return queryForOne(User.class,sql,username,password);
}
@Override
public int saveUser(User user) {
String sql="insert into t_user(`username`,`password`,`email`) values(?,?,?)";
return update(sql,user.getUsername(),user.getPassword(),user.getEmail());
}
}
测试:
在UserDao中按快捷键alt+insert,选择Test,修改测试包为JUnit4,并修改生成地址进test中,选择要测试的方法。
public class UserDaoTest {
UserDaoImpl userDao = new UserDaoImpl();
@Test
public void queryUserByUsername() {
if(userDao.queryUserByUsername("admin")==null){
System.out.println("用户名可用!");
}else {
System.out.println("用户名已存在!");
}
}
@Test
public void queryUserByUsernameAndPassword() {
if (userDao.queryUserByUsernameAndPassword("admin","admin")==null){
System.out.println("用户名或密码错误,登陆失败");
}else {
System.out.println("查询成功");
}
}
@Test
public void saveUser() {
System.out.println(userDao.saveUser(new User(null,"azhe","123456","www@162.com")));
}
}
16.6 编写UserService和测试
编写UserService类
public interface UserService {
// 注册用户
public void registerUser(User user);
// 登录
public User login(User user);
//检查用户名是否可用
public boolean existsUsername(String username);
}
编写UserServiceImpl - - -实现UserService(具有判断方法)
public class UserServiceImpl implements UserService {
private UserDao userDao=new UserDaoImpl();
@Override
public void registerUser(User user) {
userDao.saveUser(user);
}
@Override
public User login(User user) {
return userDao.queryUserByUsernameAndPassword(user.getUsername(), user.getPassword());
}
@Override
public boolean existsUsername(String username) {
if (userDao.queryUserByUsername(username)==null){
//等于null说明没查到
return false;
}
return true;
}
}
测试:
在UserService中按快捷键alt+insert,选择Test,修改测试包为JUnit4,并修改生成地址进test中,选择要测试的方法。
public class UserServiceTest {
UserService userService=new UserServiceImpl();
@Test
public void registerUser() {
userService.registerUser(new User(null,"bjpo","123","bjpo@qq.com"));
userService.registerUser(new User(null,"bo","123678","bo@qq.com"));
}
@Test
public void login() {
System.out.println(userService.login(new User(null,"bo","123678","bo@qq,com")));
}
@Test
public void existsUsername() {
if (userService.existsUsername("bo")){
System.out.println("用户名已存在!");
}else {
System.out.println("用户名可用!");
}
}
}
16.7 编写web层
1)实现用户注册的功能
RegisterServlet类代码如下: Servlet程序,运用到了请求转发
public class RegisterServlet extends HttpServlet {
private UserService userService=new UserServiceImpl();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//因为有密码,doGet得到信息会在地址栏显示,故采用doPost
//1、获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");
//2、检查 验证码是否正确 写死-要求验证码为:abcde
if ("abcde".equalsIgnoreCase(code)){
//正确
//3、检查 用户名是否可用
if (userService.existsUsername(username)){
// 已存在 不可用
// 跳回注册页面
System.out.println("用户名["+username+"]已存在!");
request.getRequestDispatcher("/pages/user/regist.html").forward(request,response);
}else {
//可用
// 调用Service保存到数据库
userService.registerUser(new User(null,username,password,email));
//跳到注册成功页面 regist_success.html
request.getRequestDispatcher("/pages/user/regist_success.html").forward(request,response);
}
}else {
// 不正确
// 跳回注册页面 ---请求转发
System.out.println("验证码["+ code +"]错误");
request.getRequestDispatcher("/pages/user/regist.html").forward(request,response);
}
}
}
2)实现用户登录的功能
LoginServlet类代码如下: Servlet程序,运用到了请求转发
public class LoginServlet extends HttpServlet {
private UserService userService=new UserServiceImpl();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、获取请求的参数
String username = request.getParameter("username");
String password = request.getParameter("password");
//2、调用xxxService.xxx()处理业务
// userService.login()登录
User loginUser = userService.login(new User(null, username, password, null));
//如果等于null,说明登录失败
if (loginUser==null){
// 失败
// 调回登录页面
request.getRequestDispatcher("/pages/user/login.html").forward(request,response);
}else {
// 成功
// 调到成功页面login_success.html
request.getRequestDispatcher("/pages/user/login_success.html").forward(request,response);
}
}
}