JavaWeb-Tomcat、Servlet

一、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);
        }

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值