Spring MVC详解

第九章 Spring MVC框架

1.什么是MVC

MVC是一种设计模式,MVC分别代表

M:Model模型

包括业务层(Java Bean)和数据库访问层(JDBC)
V:View视图

JSP页面与用户交互,对于用户输入的数据,将其交给控制器(Controller)进行处理

C:Controller控制器

沟通Model和View,控制器(Controller,由servlet类充当)接收到用户在视图(View)提交的请求后,调用Model(模型)中的组件来处理请求,然后调用相应的View(视图)来显示模型(Model)返回的数据

1.MVC模式实现对于数据库查询、分页、登录和注册、CRDU操作

(1)数据库查询

首先创建实体类用于将数据库中的数据进行封装

然后创建模型,设置对于数据库中数据的操作

最后创建控制器,由servlet担任控制器的角色

(2)分页操作

分页操作需要使用到超链接标签

<a href="">[下一页]</a>

当未指定跳转页面时,用户点击该链接时,浏览器将刷新该页面,即重新向服务器发送当前页面的请求,同时如果设置参数的话,也可以实行参数的传递

<a href="?start=${next}">[下一页]</a>

将获取到的next参数值,赋值给start

(当用户点击这个链接并传递参数后,浏览器将向服务器发送一个请求,并在查询字符串中传递参数。服务器将使用这些参数生成下一页的内容,并将其作为响应发送回浏览器。浏览器随后将刷新页面以显示新的内容。因此,这个链接会刷新当前页面并显示下一页的内容。)

关键代码如下:

package servlet;
 
import java.io.IOException;
import java.util.List;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import bean.Hero;
import dao.HeroDAO;
 
public class HeroListServlet extends HttpServlet {
	// post/get请求方法都会调用service()方法
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    	response.setContentType("text/html;charset=utf-8");
    	int start = 0;
    	int count = 5;    
        try {
        	// 从请求中获取start的值,实现翻页功能的核心代码
            start = Integer.parseInt(request.getParameter("start"));
        } catch (NumberFormatException e) {
            // 当浏览器没有传参数start时
        }
    	int next=start+count;
    	// 方法的重载,利用参数区别来实现参数的重载
    	// start为从request中获取到的
    	List<Hero> heros = new HeroDAO().list(start,count);
    	// 向请求中添加参数,实现参数的传递
    	request.setAttribute("next", next);
        request.setAttribute("heros", heros);
        request.getRequestDispatcher("listHero.jsp").forward(request, response);
        
    }
}

 第一次运行时,start的默认值为0,next的值加载为5

点击一次超链接后,start的值为5,next的值记载为10;

如此往复

接下来具体实现其余分页功能:上一页、首页、末页

具体关键实现代码如下:

C:控制器

package servlet;
 
import java.io.IOException;
import java.util.List;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import bean.Hero;
import dao.HeroDAO;
 
public class HeroListServlet extends HttpServlet {
	// post/get请求方法都会调用service()方法
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    	response.setContentType("text/html;charset=utf-8");
    	int start = 0;
    	int count = 5;    
        try {
        	// 从请求中获取start的值,实现翻页功能的核心代码
            start = Integer.parseInt(request.getParameter("start"));
        } catch (NumberFormatException e) {
            // 当浏览器没有传参数start时
        }
    	int next=start+count;
    	int pre = start-count;
    	int end;
    	// 末页的计算方相对复杂
    	// 首先获取数据的总数,调用DAO中的对应方法
    	HeroDAO heroDAO= new HeroDAO();
    	int total = heroDAO.getTotal();
    	// 没有余页时,即每一页都有count条数据
    	if (total%count==0){
    		end=total-count;
    	}
    	// 存在余页时
    	else{
    		end=total-total%count;
    	}
    	// 方法的重载,利用参数区别来实现参数的重载
    	// start为从request中获取到的
    	List<Hero> heros = new HeroDAO().list(start,count);
    	// 向请求中添加参数,实现参数的传递
    	request.setAttribute("next", next);
        request.setAttribute("heros", heros);
        request.setAttribute("pre", pre);
        request.setAttribute("end", end);
        request.getRequestDispatcher("listHero.jsp").forward(request, response);
        
    }
}

 M:模型

package bean;
  
public class Hero {
  
    public int id;
    public String name;
    public float hp;
    public int damage;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public float getHp() {
        return hp;
    }
    public void setHp(float hp) {
        this.hp = hp;
    }
    public int getDamage() {
        return damage;
    }
    public void setDamage(int damage) {
        this.damage = damage;
    }
      
}

在实现分页功能的操作中,只需要用到DAO中的部分方法getTotal();list(int start,int count) 

package dao;
   
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
  
import bean.Hero;
   
public class HeroDAO {
   
    public HeroDAO() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
   
    public Connection getConnection() throws SQLException {
        return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8", "root",
                "123456");
    }
   
    public int getTotal() {
        int total = 0;
        try (Connection c = getConnection(); Statement s = c.createStatement();) {
   
            String sql = "select count(*) from hero";
   
            ResultSet rs = s.executeQuery(sql);
            while (rs.next()) {
                total = rs.getInt(1);
            }
   
            System.out.println("total:" + total);
   
        } catch (SQLException e) {
   
            e.printStackTrace();
        }
        return total;
    }
   
   
    public List<Hero> list() {
        return list(0, Short.MAX_VALUE);
        // 方法的重载
        // 用参数进行区别
        // 调用下面的lis(int start,int conut)方法
    }
   
    
    public List<Hero> list(int start, int count) {
        List<Hero> heros = new ArrayList<Hero>();
   
        String sql = "select * from hero order by id asc limit ?,? ";
        //这是一个SQL查询语句,用于从hero表中按id倒序排列并限制返回结果的数量。其中,问号表示需要通过PreparedStatement设置的参数。
        //第一个问号表示偏移量(即从第几条记录开始返回),第二个问号表示返回的记录数量。这种使用PreparedStatement的方式可以有效地避免SQL注入攻击。
   
        try (Connection c = getConnection(); PreparedStatement ps = c.prepareStatement(sql);) {
        	// 设置参数
            ps.setInt(1, start);
            ps.setInt(2, count);
   
            ResultSet rs = ps.executeQuery();
   
            while (rs.next()) {
                Hero hero = new Hero();
                int id = rs.getInt(1);
                String name = rs.getString(2);
                float hp = rs.getFloat("hp");
                int damage = rs.getInt(4);
                hero.id = id;
                hero.name = name;
                hero.hp = hp;
                hero.damage = damage;
                heros.add(hero);
            }

        } catch (SQLException e) {
   
            e.printStackTrace();
        }
        return heros;
    }
   
}

 V:view

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="java.util.*"%>
 
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 
<table align='center' border='1' cellspacing='0'>
    <tr>
        <td>id</td>
        <td>name</td>
        <td>hp</td>
        <td>damage</td>
        <td>edit</td>
        <td>delete</td>
    </tr>
    <c:forEach items="${heros}" var="hero" varStatus="st">
        <tr>
            <td>${hero.id}</td>
            <td>${hero.name}</td>
            <td>${hero.hp}</td>
            <td>${hero.damage}</td>
            <td><a href="editHero?id=${hero.id}">edit</a></td>
            <td><a href="deleteHero?id=${hero.id}">delete</a></td>
        </tr>
    </c:forEach>
    <tr>
    	<td colspan="6" align="center">
    		<a href="?start=0">[首页]</a>
    		<a href="?start=${next}">[下一页]</a>
    		<a href="?start=${pre}">[上一页]</a>
    		<a href="?start=${end}">[末页]</a>
    	</td>
    </tr>
</table>

 (3.)登录和注册

首先需要设置用户的登录界面,提交用户填写的表单form

然后将获取的表单信息提交给对应的控制器处理

(4)CRDU操作

最终运行结果如下:

 CRDU操作在上述中都有所体现

具体关键代码如下(代码太多了):

放到另一个文章中去。

2.什么是Spring MVC及其工作原理

1.什么是Spring MVC

Spring MVC是一个基于Spring框架的Web应用程序开发框架,它允许开发人员使用模型-视图-控制器(MVC)的设计模式来构建Web应用程序。

2.Spring MVC工作原理

首先web服务器接收到HTTP请求后,根据url地址(请求的路径)为其分配DiapatchServlet(前端控制器),然后根据请求的信息为其分配控制器(controller),控制器中调用模型(model)中的方法(业务层)来处理请求,然后将返回结果返回到指定的视图(view)进行显示。

ps:在Spring MVC框架中存在两个映射文件

web.xml映射文件

web.xml映射文件的主要作用是将所有HTTP请求交给DispatchServlet来处理(用于启动DispatchServlet),后续具体的分配控制器来处理请求,就交给了另一个映射文件来进行。

web.xml映射文件的具体代码如下:(里面的注释还是值得一看的

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        
    <!-- 指定另一个配置文件的位置 -->
    <init-param>
	    <param-name>contextConfigLocation</param-name>
	    <param-value>/WEB-INF/servlet.xml</param-value>
	</init-param>
	
	<!-- 设置DispatherServlet加载的次序,即第一个加载 -->
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

在Spring MVC框架中,web.xml映射文件的唯一作用就是将所有请求交给DisptcherServlet来处理

spring-servlet.xml映射文件

spring-servlet.xml映射文件时Spring MVC框架中配置不同的控制器来处理对应的HTTP请求,在spring-servlet.xml映射文件中主要的作用我认为有两个:

1.为HTTP请求分配对于的控制器,对请求进行处理

分配方式就有多种,最常用使用的是使用注解方式,在类的前面加上@Controller表明其是一个控制器,而不是通过实行接口的方式。并且配置spring-servlet.xml映射文件也会高效很多,不需要使用<bean>标签来请求地址和控制器的一一对应。

只需要在spring-servlet.xml映射文件中设置好要进行扫描的包,并且在类的方法中使用@(“/url地址”)来实行请求路径和控制器的一一对应。

2.定位视图的位置

在控制器处理完请求后会返回一个结果,结果的展示就需要通过spring-servlet.xml映射文件来匹配对应的jsp视图文件

具体工作原理由下述代码来具体体现

spring-servlet.xml映射文件的具体代码如下:

首先是采用非注解的方式(对应的Controller类要实现controller接口)
servlet.xml映射文件具体代码如下:

在servlet.xml映射文件中配置HandleMapping为不同的请求分配控制器来进行处理

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="simpleUrlHandlerMapping"
        class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props><!--HandleMapping设置各种请求-->
                <prop key="/index">indexController</prop>
            </props>
        </property>
    </bean>
    <!--设置对应请求对应的控制器所在位置-->
    <bean id="indexController" class="controller.IndexController"></bean>
</beans>

 对应的控制器类具体代码如下:

package controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class IndexController implements Controller{
	public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response){
		// 控制器方法执行后,会将数据模型和视图名称一起返回给前端页面进行渲染。
		ModelAndView mav = new ModelAndView("index.jsp");
		mav.addObject("message","Hello Spring MVC");
		return mav;
	}
}

对应的index.jsp页面代码如下(注意本次servlet.xml文件没有指定jsp前端页面的位置,所以要在WebContent文件夹下创建):

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
	<h1>${message}</h1>
	</body>
</html>

 具体运行结果如下:

 由上述代码中的注释可以很明显的感觉到servlet.xml映射文件的这种配置方式非常繁琐,要处理多少个不同的请求就要配置多少次,这种重复的工作人为完成性价比不高。

---------------------------------------------------------------------------------------------------------------------------------

接下来采用注解方式来配置servlet.xml映射文件同时指定前端页面位置

servlet.xml映射文件的具体代码如下:(注释还是值得一看的)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context        
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    <!-- 指定进行扫描的范围 -->
    <context:component-scan base-package="controller" />
    <!-- 指定前端页面的位置 -->
    <bean id="irViewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/page/" />
        <!-- 指定了后缀,则在控制器中就不用带jsp后缀了 -->
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

 控制器类具体代码如下:

package controller;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.stereotype.Controller;

@Controller
public class IndexController {
	@RequestMapping("/index")
	public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response){
		// 控制器方法执行后,会将数据模型和视图名称一起返回给前端页面进行渲染。
		ModelAndView mav = new ModelAndView("index");
		mav.addObject("message","Hello Spring MVC");
		return mav;
	}
}

 前端代码不变,但是位置要与servlet.xml映射文件中的对应

3.MVC和Spring MVC的关系

Spring MVC是一种基于MVC模式的Web应用程序开发框架,它使用MVC模式来组织和管理代码,使得Web应用程序更易于维护和扩展。

4.请求映射与参数绑定(参数绑定过程)

请求映射和参数的绑定主要是通过注解模式来实现的

在前文中servlet.xml映射文件已经配置好了,使用注解模式来处理请求,在一个项目中配置文件一般一次性配置好之后,就不用再管它了。

再通过实例来展示请求映射和参数的绑定

具体流程如下:

将用户提交的表单数据进行传递和展示

具体代码如下:、

封装数据的实体类

package pojo;

public class Product {
	public String name;
	public float price;
	
	// 设置set、get方法实现数据的封装
	public void setName(String name){
		this.name=name;
	}
	public void setPrice(float price){
		this.price=price;
	}
	
	public String getName(){
		return name;
	}
	public float getPrice(){
		return price;
	}
}

用户提交页面:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
	<form action="addProduct" method="post">
	name:<input type="text" name="name"><br>
	price:<input type="text" name="price"><br>
	<input type="submit" value="添加">
	</form>
	</body>
</html>

 处理请求控制器

package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import pojo.Product;
@Controller
public class AddProduct {
	@RequestMapping("/addProduct")
	// Spring MVC 框架会自动根据表单参数名称和 Product 类的属性名称进行匹配,并自动将相应的表单参数值赋给 Product对象的属性值。
	public ModelAndView AddProduuct(Product product){
		ModelAndView mav = new ModelAndView();
		mav.setViewName("showProduct");
		return mav;
	}
}

 展示页面:

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
	product:<a>${product.name}</a><br>
	price:<a>${product.price}</a>
	</body>
</html>

 结果展示:

 

 这个过程中会出现乱码:

再Spring MVC框架中解决的方法之一是再web.xml配置文件中加上一个filter,更新后的代码具体如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        
    <!-- 指定另一个配置文件的位置 -->
    <init-param>
	    <param-name>contextConfigLocation</param-name>
	    <param-value>/WEB-INF/servlet.xml</param-value>
	</init-param>
	
	<!-- 设置DispatherServlet加载的次序,即第一个加载 -->
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    
    <!-- 设置过滤器 -->
    <filter>
    	<filter-name>EncodingFilter</filter-name>
    	<!-- 使用Spring MVC框架自带的实现过滤的类,不需要自己编写 -->
    	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    	<init-param>
    		<param-name>encoding</param-name>
    		<param-value>UTF-8</param-value>
    	</init-param>
    </filter>
    <filter-mapping>
    	<filter-name>EncodingFilter</filter-name>
    	<url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

 另外的参数传递的方法:

超链接

 控制类:

 运行的结果:

 成功实现参数的传递

还有几种参数传递的方法,原理都很简单,网上自行搜索即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring MVC 是一种基于 Java 的开发框架,用于构建 Web 应用程序。它是 Spring 框架的一部分,提供了一种模型-视图-控制器(MVC)的架构模式,帮助开发人员将应用程序的不同方面进行解耦。 在 Spring MVC 中,应用程序的请求由 DispatcherServlet 接收并将其路由到适当的处理程序(也称为控制器)。控制器处理请求并生成模型数据,然后选择适当的视图来呈现这些模型数据给用户。 以下是 Spring MVC 的一些重要组件和概念: 1. DispatcherServlet:是整个 Spring MVC 的中央调度器,负责接收请求并将其分派给相应的处理程序。 2. 控制器(Controller):处理请求的组件,根据请求的类型和内容执行逻辑处理,并生成模型数据。 3. 模型(Model):表示应用程序的数据和状态。控制器可以通过模型对象来设置和获取数据,并将其传递给视图进行呈现。 4. 视图(View):负责将模型数据呈现给用户。可以是 JSP、Thymeleaf 或其他模板引擎。 5. 处理器映射器(Handler Mapping):将请求映射到相应的处理程序(控制器)。它根据配置文件或注解来确定请求与处理程序之间的映射关系。 6. 视图解析器(View Resolver):根据视图名称解析出实际的视图对象,它将逻辑视图名转换为物理视图。 7. 拦截器(Interceptor):在请求处理的过程中,可以对请求进行预处理和后处理。可以用于身份验证、日志记录等功能。 8. 数据绑定(Data Binding):自动将请求参数绑定到控制器方法的参数或模型对象的属性上。 9. 校验器(Validator):用于验证模型对象的数据的有效性。 Spring MVC 提供了灵活且强大的功能,使开发人员能够轻松构建可扩展和可维护的 Web 应用程序。它还支持 RESTful Web 服务和国际化等功能。通过良好的设计和组织,Spring MVC 可以实现松耦合、可测试和可扩展的应用程序架构。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值