MVC&三层架构&Servlet

MVC

MVC(Model View Controller)是软件工程中的一种软件架构模式,它把软件系统分为模型视图控制器三个基本部分。以一种业务逻辑、界面显示、数据分离的方式组织代码,将业务逻辑聚集到一个部件里面(模型),在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

网页获取动态资源逻辑

  1. 网页界面
  2. 请求转发
  3. 接收请求
  4. 处理请求
  5. 返回数据

定义

  • M:Model,模型。
    • 完成具体的业务操作,如:查询数据库,封装对象
  • V:view视图。JSP、HTML等来进行数据展示
  • C:Controller控制器。 Servlet
    • 获取View的请求
    • 调用模型将数据交给视图进行展示

举个🌰

img

控制器Controller 的作用就是将ModelView一一对应起来

优缺点

【优点】

  1. 耦合性低,方便维护,可以利于分工协作
  2. 重用性高

【缺点】

  1. 使得项目架构变得复杂,对开发人员要求高

参考博客

MVC与三层架构理解

三层架构

img

通常意义上的三层架构就是将整个业务应用划分为:界面层[表示层] UI(User Interface layer)、业务逻辑层BLL(Business Logic Layer)、数据访问层DAL(Data access layer)。

区分层次的目的是为了“高内聚低耦合” 的思想

举个🌰

img

任何一层发生变化都不会影响到另外一层!!!

优缺点

【优点】

  1. 开发人员可以只关注整个结构中的其中某一层;
  2. 可维护性高,可扩展性高
  3. 可以降低层与层之间的依赖;
  4. 有利于标准化;
  5. 利于各层逻辑的复用

【缺点】

  1. 降低了系统的性能。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成
  2. 有时会导致级联的修改,这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码
  3. 增加了开发成本

MVC和三层架构的区别

img

参考博客

MVC与三层架构理解

Servlet

是用Java编写的服务器程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。

工作模式

  • 客户端发送请求至服务器
  • 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器
  • 服务器将响应返回客户端

在mvc架构中,servlet在其中承担的作用是controller,控制器。

控制器作用:

  • 获取View的请求
  • 调用模型(M)将数据交给视图(V)进行展示

web应用是基于http协议的,http协议有请求报文(request)和响应报文(request),请求报文就是浏览器向服务器发送的数据形成的数据对象,同理,响应报文就是服务器向浏览器发送的数据形成的信息,而http协议有两个重要的方法,一个是POST,一个是GET,这两个方法就是向浏览器发送请求的方法。

servlet能够读取请求报文的内容,并对报文进行处理。

Servlet的开发流程

狭义上讲,servlet是java语言实现的一个类,所以我们就要根据这个类进行相应的扩展开发。

具体流程如下:

  1. 编写一个java类,继承HttpServlet类(需要导入servlet-api.jar
  2. 重写HttpServlet类的doGet方法和doPost方法
  3. 配置web.xml文件,或者使用注解对servlet进行配置

web.xml配置servlet

配置格式示例

<webapp>
<!-- 配置一个servlet -->
  <!-- servlet的配置 -->
  <servlet>
  	<!-- servlet的内部名称,自定义。尽量有意义 -->
  	<servlet-name>MyServlet</servlet-name>
  	<!-- servlet的类全名: 包名+简单类名 -->
  	<servlet-class>cn.roobtyan.servlet.FirstServlet</servlet-class>
  	<init-param>
            <param-name>first</param-name>
            <param-value>第一个初始化参数</param-value>
        </init-param>
        <init-param>
            <param-name>second</param-name>
            <param-value>第二个初始化参数</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
  </servlet>
  
  <!-- servlet的映射配置 -->
  <servlet-mapping>
  	<!-- servlet的内部名称,一定要和上面的内部名称保持一致!! -->
  	<servlet-name>MyServlet</servlet-name>
  	<!-- servlet的映射路径(访问servlet的名称),"/"斜杠不能省略-->
  	<url-pattern>/first</url-pattern>
  </servlet-mapping>
</webapp>

访问/first的时候,服务器会把请求交给MyServlet进行处理。


标记容器何时加载servlet(实例化并调用init()方法)
为负值或者没有配置 ,则容器会当Servlet被请求时加载
为正整数或者0,则容器在应用启动时就加载并初始化
值越小,servlet的优先级越高,就越先被加载。值相同时,容器就会自己选择顺序来加载。

@注解配置servlet

@WebServlet(name = "LoginServlet",urlPatterns = {"/login"})
public class LoginServlet extends HttpServlet {

映射路径通配符

/*				#任意路径都映射到这个servlet
/bluemson/*		#/bluemsun下的任意路径映射到该servlet

url要么以/开头,要么以*开头,其他的都是非法的

Servlet的生命周期

一般来讲,servlet只会初始化一次,也就是整个过程中只存在一个servlet对象,即便是有多次访问,依然只有一个对象,这个对象是可以复用的。

所以servlet是单实例多线程的。

Servlet接口

public interface Servlet {

    void init(ServletConfig var1) throws ServletException;
 		//获得ServletConfig
    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
 
    String getServletInfo();
 
    void destroy();
}

其中init(),service(),destroy()比较关键,体现了Servlet的生命周期。

  • init方法只会调用一次,只是在创建servlet实例的时候才会创建

  • service方法,是进行数据处理的,只要接受了一次请求,就会被调用一次

  • destroy方法,销毁servlet对象的时候调用。停止服务器或者重新部署web应用时销毁servlet对象,同样也是调用一次

ServletConfig接口

public interface ServletConfig {
  	//返回当前servlet的名字
    String getServletName();
		//返回ServletContext(web应用的上下文)
  	//每个web应用对应一个ServletContext,定义了servlet用来与servlet容器通信的多种方法
    ServletContext getServletContext();
		//可以根据名字来获取servlet的初始化参数
    String getInitParameter(String var1);
		//获取出初始化参数的参数名
    Enumeration<String> getInitParameterNames();
}

HttpServlet抽象类

虽然是抽象类但是没有抽象方法!

为什么?

每次要新建一个servlet都要实现Servlet接口,重写这好几个方法太麻烦啦!于是GenericServlet抽象类出现了。

GenericServlet抽象类

该类实现了Servlet, ServletConfig两个接口并重写了方法。

在这里插入图片描述

//只有一个抽象方法在继承GenericServlet时要实现
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

注意这里有两个重载的init()方法

  • init(ServletConfig)是 GenericServlet 抽象类实现 servlet接口要实现的init方法,实现了原来Servlet的功能
  • init()是GenericServlet 抽象了自己新添加的init方法,目的是让继承该抽象类的servlet被加载并初始化时可以自己做些自定义的初始化

这时,如果我们继承GenericServlet 抽象类再写servlet已经简单多了。而继承了它的HttpServlet更加简单。

回到HttpServlet

该抽象类继承了GenericServlet 抽象类,并且重写了GenericServlet 中唯一的抽象方法service(ServletRequest,ServletRespone)方法
在这里插入图片描述

其中重点看两个重载的service方法

  • service(ServletRequest , ServletResponse)

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
      			//下转型为HttpServletRequest(ServletRequest子接口)
            HttpServletRequest request;
      			//下转型为HttpServletRespone(ServletRespone子接口)
            HttpServletResponse response;
            try {
                request = (HttpServletRequest)req;
                response = (HttpServletResponse)res;
            } catch (ClassCastException var6) {
                throw new ServletException(lStrings.getString("http.non_http"));
            }
    				//调用自定义的service方法
            this.service(request, response);
        }
    

    由于我们的请求都是http请求,所以把ServletRequest请求下转型为HttpServletRequest,ServletRespone请求下转型为HttpServletRespone,以获取更多关于请求的信息(如请求方式等),并调用自定义的service方法

  • service(HttpServletRequest, HttpServletResponse)自定义方法,根据请求的方式去调用不同的方法

当我们新建servlet的时候只需要继承HttpServlet,然后根据请求方式重写对应的doXXX()方法就行了

为什么定义成抽象类?

防止直接创建对象!单纯的HttpServlet对象时不能处理任何业务逻辑的,里边方法没有功能,需要继承它我们重写它的方法!

Servlet中四个重要的对象

HttpServletRequest  请求对象:获取请求信息
HttpServletResponse 响应对象: 设置响应对象
ServletConfig对象    servlet配置对象
ServletContext对象  servlet的上下文对象

在这里插入图片描述

对应关系:Servlet与JSP九大内置对象的对应关系

这些上节课学姐的博客里也写的很详细了

蓝旭第四次培训——JSP

转发和重定向

转发

request.getRequestDispatcher("loginfal.jsp").forward(req,resp);

重定向

与转发功能相似的是重定向,重定向的使用是这样的:

response.sendRedirect("loginfal.jsp");

这样也会访问到loginfal.jsp这个页面。

转发和重定向的区别

虽然二者最终实现的功能是相同的.但是还是有很大不同的.不同之处如下:

  1. 地址栏变化
    转发不会改变地址栏中的URL,而重定向则会改变
  2. 跳转范围
    转发只能访问到当前web应用中的内容,而重定向则可以访问到任意web应用中的内容
  3. request对象作用范围
    转发后,在转发后的页面中仍然可以使用原来的request对象,而重定向,原来的request对象则失去作用.

所以,如果想要在多个页面使用相同的request对象,那么只能使用转发,而不能使用重定向。

一个Servlet小demo

register.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>注册界面</title>
</head>
<body>
<form action="/register" method="get">
    账号:<input type="text" name="name">
    <br>
    密码:<input type="password" name="password">
    <br>
    <input type="submit" value="注册">
</form>
</body>
</html>

Register.java

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class Register extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        String password = req.getParameter("password");
        HttpSession session = req.getSession();
        User user = new User();
        user.setName(name);
        user.setPassword(password);
        session.setAttribute("user",user);
//        req.getRequestDispatcher("registersuc.jsp").forward(req,resp);


        //设置响应的编码格式为UTF-8编码,否则发生中文乱码现象
        resp.setContentType("text/html;charset=UTF-8");
        //1.获得请求方式
        String method = req.getMethod();
        //2.获得请求的资源相关的内容
        //获得请求URI
        String requestURI = req.getRequestURI();
        //获得应用路径(应用名称)
        String webName = req.getContextPath();
        //获得查询字符串
        String querryString = req.getQueryString();

        resp.getWriter().write("<h1>下面是获得的字符串</h1>");
        resp.getWriter().write("<h1>method(HTTP方法):<h1>");
        resp.getWriter().write("<h1>"+method+"</h1><br>");
        resp.getWriter().write("<h1>requestURi(请求URI):</h1>");
        resp.getWriter().write("<h1>" + requestURI + "</h1><br>");
        resp.getWriter().write("<h1>webname(应用名称):</h1>");
        resp.getWriter().write("<h1>" + webName + "</h1><br>");
        resp.getWriter().write("<h1>querrystring(查询字符串):</h1>");
        resp.getWriter().write("<h1>" + querryString + "</h1>");

//        resp.sendRedirect("registersuc.jsp");
    }
}

web.xml

		<servlet>
        <servlet-name>regiter</servlet-name>
        <servlet-class>Register</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>regiter</servlet-name>
        <url-pattern>/register</url-pattern>
    </servlet-mapping>

jsp界面:

在这里插入图片描述

注册后显示的结果:

在这里插入图片描述

小结

img

参考博客

Servlet详细教程

JavaWeb——Servlet(全网最详细教程包括Servlet源码分析)

servlet入门&MVC

理解HttpServlet抽象类没有抽象方法(从Servlet–GenericServlet–HttpServlet)

servlet官方文档

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值