[Java EE] Explicação detalhada do processo de desenvolvimento do Spring MVC

Processo de desenvolvimento do Spring MVC


Com a configuração inicial acima, não é difícil desenvolver o processo Spring MVC. Para desenvolver programas Spring MVC, você precisa dominar os componentes e processos do Spring MVC, para que o processo de desenvolvimento também seja executado no processo de operação do Spring MVC.

No processo de desenvolvimento atual, a maioria deles usará métodos de desenvolvimento anotados. O uso de anotações no Spring MVC é muito simples, principalmente marcado com uma anotação @Controller, geralmente só precisa verificar a configuração, você pode digitalizá-la, mas geralmente combinado com a anotação @RequestMapping para configurá-la. O @RequestMapping pode ser configurado sobre uma classe ou método, cuja função é especificar o URI e qual classe (ou método) como um processador que processa solicitações.Para obter mais flexibilidade, o Spring MVC também define um interceptador para o processador. Quando o MVC, o Spring MVC analisa a configuração do @RequestMapping no @Controller e depois combina os interceptores configurados, para formar vários interceptores e um controlador na forma de HandlerMapping. Quando a solicitação chega ao servidor, a primeira é encontrar o HandlerMapping correspondente através das informações da solicitação e, em seguida, o interceptador e o processador correspondentes podem ser encontrados, para que o controlador e o interceptador correspondentes possam ser executados.

1. Configure o @RequestMapping

O código fonte do @RequestMapping é o seguinte:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {

	/**
	 * Assign a name to this mapping.
	 * <p><b>Supported at the type level as well as at the method level!</b>
	 * When used on both levels, a combined name is derived by concatenation
	 * with "#" as separator.
	 * @see org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder
	 * @see org.springframework.web.servlet.handler.HandlerMethodMappingNamingStrategy
	 */
        // 请求路径
	String name() default "";

	/**
	 * The primary mapping expressed by this annotation.
	 * <p>In a Servlet environment this is an alias for {@link #path}.
	 * For example {@code @RequestMapping("/foo")} is equivalent to
	 * {@code @RequestMapping(path="/foo")}.
	 * <p>In a Portlet environment this is the mapped portlet modes
	 * (i.e. "EDIT", "VIEW", "HELP" or any custom modes).
	 * <p><b>Supported at the type level as well as at the method level!</b>
	 * When used at the type level, all method-level mappings inherit
	 * this primary mapping, narrowing it for a specific handler method.
	 */
        // 请求路径,可以是数组
	@AliasFor("path")
	String[] value() default {};

	/**
	 * In a Servlet environment only: the path mapping URIs (e.g. "/myPath.do").
	 * Ant-style path patterns are also supported (e.g. "/myPath/*.do").
	 * At the method level, relative paths (e.g. "edit.do") are supported within
	 * the primary mapping expressed at the type level. Path mapping URIs may
	 * contain placeholders (e.g. "/${connect}")
	 * <p><b>Supported at the type level as well as at the method level!</b>
	 * When used at the type level, all method-level mappings inherit
	 * this primary mapping, narrowing it for a specific handler method.
	 * @see org.springframework.web.bind.annotation.ValueConstants#DEFAULT_NONE
	 * @since 4.2
	 */
        // 请求路径,数组
	@AliasFor("value")
	String[] path() default {};

	/**
	 * The HTTP request methods to map to, narrowing the primary mapping:
	 * GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.
	 * <p><b>Supported at the type level as well as at the method level!</b>
	 * When used at the type level, all method-level mappings inherit
	 * this HTTP method restriction (i.e. the type-level restriction
	 * gets checked before the handler method is even resolved).
	 * <p>Supported for Servlet environments as well as Portlet 2.0 environments.
	 */
        // 请求类型,比如是HTTP的GET请求还是POST请求等,HTTP请求枚举取值范围为:GET、HEAD、PUT、PATCH、DELETE、OPTIONS、TRACE,常用的是GET和POST请求
	RequestMethod[] method() default {};

	/**
	 * The parameters of the mapped request, narrowing the primary mapping.
	 * <p>Same format for any environment: a sequence of "myParam=myValue" style
	 * expressions, with a request only mapped if each such parameter is found
	 * to have the given value. Expressions can be negated by using the "!=" operator,
	 * as in "myParam!=myValue". "myParam" style expressions are also supported,
	 * with such parameters having to be present in the request (allowed to have
	 * any value). Finally, "!myParam" style expressions indicate that the
	 * specified parameter is <i>not</i> supposed to be present in the request.
	 * <p><b>Supported at the type level as well as at the method level!</b>
	 * When used at the type level, all method-level mappings inherit
	 * this parameter restriction (i.e. the type-level restriction
	 * gets checked before the handler method is even resolved).
	 * <p>In a Servlet environment, parameter mappings are considered as restrictions
	 * that are enforced at the type level. The primary path mapping (i.e. the
	 * specified URI value) still has to uniquely identify the target handler, with
	 * parameter mappings simply expressing preconditions for invoking the handler.
	 * <p>In a Portlet environment, parameters are taken into account as mapping
	 * differentiators, i.e. the primary portlet mode mapping plus the parameter
	 * conditions uniquely identify the target handler. Different handlers may be
	 * mapped onto the same portlet mode, as long as their parameter mappings differ.
	 */
        // 请求参数,当请求带有配置的参数时,才匹配处理器
	String[] params() default {};

	/**
	 * The headers of the mapped request, narrowing the primary mapping.
	 * <p>Same format for any environment: a sequence of "My-Header=myValue" style
	 * expressions, with a request only mapped if each such header is found
	 * to have the given value. Expressions can be negated by using the "!=" operator,
	 * as in "My-Header!=myValue". "My-Header" style expressions are also supported,
	 * with such headers having to be present in the request (allowed to have
	 * any value). Finally, "!My-Header" style expressions indicate that the
	 * specified header is <i>not</i> supposed to be present in the request.
	 * <p>Also supports media type wildcards (*), for headers such as Accept
	 * and Content-Type. For instance,
	 * <pre class="code">
	 * &#064;RequestMapping(value = "/something", headers = "content-type=text/*")
	 * </pre>
	 * will match requests with a Content-Type of "text/html", "text/plain", etc.
	 * <p><b>Supported at the type level as well as at the method level!</b>
	 * When used at the type level, all method-level mappings inherit
	 * this header restriction (i.e. the type-level restriction
	 * gets checked before the handler method is even resolved).
	 * <p>Maps against HttpServletRequest headers in a Servlet environment,
	 * and against PortletRequest properties in a Portlet 2.0 environment.
	 * @see org.springframework.http.MediaType
	 */
        // 请求头,当HTTP请求头为配置项时,才匹配处理器
	String[] headers() default {};

	/**
	 * The consumable media types of the mapped request, narrowing the primary mapping.
	 * <p>The format is a single media type or a sequence of media types,
	 * with a request only mapped if the {@code Content-Type} matches one of these media types.
	 * Examples:
	 * <pre class="code">
	 * consumes = "text/plain"
	 * consumes = {"text/plain", "application/*"}
	 * </pre>
	 * Expressions can be negated by using the "!" operator, as in "!text/plain", which matches
	 * all requests with a {@code Content-Type} other than "text/plain".
	 * <p><b>Supported at the type level as well as at the method level!</b>
	 * When used at the type level, all method-level mappings override
	 * this consumes restriction.
	 * @see org.springframework.http.MediaType
	 * @see javax.servlet.http.HttpServletRequest#getContentType()
	 */
        // 请求类型为配置类型才匹配处理器
	String[] consumes() default {};

	/**
	 * The producible media types of the mapped request, narrowing the primary mapping.
	 * <p>The format is a single media type or a sequence of media types,
	 * with a request only mapped if the {@code Accept} matches one of these media types.
	 * Examples:
	 * <pre class="code">
	 * produces = "text/plain"
	 * produces = {"text/plain", "application/*"}
	 * produces = "application/json; charset=UTF-8"
	 * </pre>
	 * <p>It affects the actual content type written, for example to produce a JSON response
	 * with UTF-8 encoding, {@code "application/json; charset=UTF-8"} should be used.
	 * <p>Expressions can be negated by using the "!" operator, as in "!text/plain", which matches
	 * all requests with a {@code Accept} other than "text/plain".
	 * <p><b>Supported at the type level as well as at the method level!</b>
	 * When used at the type level, all method-level mappings override
	 * this produces restriction.
	 * @see org.springframework.http.MediaType
	 */
        // 处理器之后的响应用户的结果类型,比如{“application/json;charset=UTF-8”,"text/plain","application/*"}
	String[] produces() default {};

}

O mais usado aqui é o caminho e o tipo de solicitação, e a maioria dos outros é usada como itens limitadores e configurada conforme necessário. Por exemplo, adicione um método index2 ao MyController, o código é o seguinte:

@RequestMapping(value = "/index2",method = RequestMethod.GET)
	public ModelAndView  index2() {
		ModelAndView mv = new ModelAndView();
		mv.setViewName("index");
		return mv;
	}

Isso fornece uma resposta à solicitação HTTP GET de /my/index2.do.

2. Desenvolvimento do controlador

O desenvolvimento do controlador é o conteúdo principal do Spring MVC, e suas etapas geralmente são divididas em três etapas.

  • Obter parâmetros de solicitação
  • Processando lógica de negócios
  • Vincular modelo e visualização

2.1 Obter parâmetros de solicitação

Há muitas maneiras de receber parâmetros no Spring MVC; é recomendável não usar a API fornecida pelo contêiner Servlet, porque o controlador dependerá do contêiner Servlet, como:

@RequestMapping(value = "/index2",method = RequestMethod.GET)
	public ModelAndView  index2(HttpSession session, HttpServletRequest request) {
		ModelAndView mv = new ModelAndView();
		mv.setViewName("index");
		return mv;
	}

O Spring MVC analisará automaticamente a sessão e os parâmetros do método no código e passará a API sobre o contêiner do Servlet, para que possa ser obtido. Por solicitação ou sessão, você pode facilmente obter os parâmetros da solicitação HTTP.Este é um método, mas não é um bom método . Como isso é feito, o método index2 está intimamente relacionado ao contêiner Servlet, que não é propício para expansão e teste. Para fornecer uma melhor flexibilidade, o Spring MVC fornece mais métodos e anotações para obter parâmetros.

Se você deseja obter o parâmetro de um ID de solicitação HTTP, ele é um número inteiro longo, é possível usar a anotação @RequestParam para obtê-lo, o código é modificado para:

@RequestMapping(value = "/index2",method = RequestMethod.GET)
	public ModelAndView  index2(@RequestParam("id") Long id) {
		System.out.println("params[id] = " + id);
		ModelAndView mv = new ModelAndView();
		mv.setViewName("index");
		return mv;
	}

Por padrão, para o parâmetro anotado com @RequestParam, ele exige que o parâmetro não esteja vazio, ou seja, quando o parâmetro de solicitação HTTP não puder ser obtido, o Spring MVC lançará uma exceção. Às vezes, também quero atribuir um valor padrão ao parâmetro.Para resolver essas dificuldades, o @RequestParam também forneceu dois itens de configuração úteis:

  • required é um booleano (booleano), o padrão é true, ou seja, o parâmetro não pode estar vazio, se você deseja permitir nulo, configure-o como false.
  • O valor padrão de defaultValue é "\ n \ t \ t \ n \ t \ t \ n \ uE000 \ uE001 \ uE002 \ n \ t \ t \ t \ t \ n", pode ser modificado para o conteúdo desejado através da configuração . 

Para obter o conteúdo da sessão, assumindo que o userName esteja definido na sessão atual, como deve ser obtido? O Spring MVC também fornece a anotação @SessionAttribute para obter os dados correspondentes da Sessão. O código é o seguinte:

@RequestMapping(value = "/index3",method = RequestMethod.GET)
	public ModelAndView  index3(@SessionAttribute("userName") String userName) {
		System.out.println("session[userName] = " + userName);
		ModelAndView mv = new ModelAndView();
		mv.setViewName("index");
		return mv;
	}

 

2.2 Implementar vistas lógicas e vinculadas

De um modo geral, a lógica implementada está relacionada ao banco de dados.Se você usa XML, você só precisa configurar a parte do banco de dados em applicationContext.xml; se você usa a configuração Java, é necessário configurar GetRootConfigClasses pode ser adicionado à classe de configuração correspondente.

Às vezes, ao usar o desenvolvimento de pacotes de terceiros, é mais conveniente usar XML do que anotações, porque não há necessidade de projetar muito código Java sobre o conteúdo de pacotes de terceiros ou mesmo uso misto.A configuração da amostra é a seguinte:

<?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:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
	<!-- 使用注解驱动 -->
	<context:annotation-config />
	<!-- 数据库连接池 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver" />
		<property name="url" value="jdbc:mysql://localhost:3306/chapter14" />
		<property name="username" value="root" />
		<property name="password" value="123456" />
		<property name="maxActive" value="255" />
		<property name="maxIdle" value="5" />
		<property name="maxWait" value="10000" />
	</bean>

	<!-- 集成mybatis -->
	<bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="configLocation" value="classpath:/mybatis/mybatis-config.xml" />
	</bean>

	<!-- 配置数据源事务管理器 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 采用自动扫描方式创建mapper bean -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	    <property name="basePackage" value="com.ssm.chapter14" />
	    <property name="SqlSessionFactory" ref="SqlSessionFactory" />
	    <property name="annotationClass" value="org.springframework.stereotype.Repository" />
	</bean>
</beans>

Supondo que o arquivo de configuração XML acima tenha inicializado um Bean-RoleService em um contêiner Spring IoC por varredura e forneça um método longo getRole para obter a função, ele poderá ser controlado por montagem automática. Nele. O código do controlador de função é o seguinte:

/**************import ***************/
@Controller
@RequestMapping("/role")
public class RoleController {
	// 注入角色服务类
	@Autowired
	private RoleService roleService = null;

	@RequestMapping(value = "/getRole", method = RequestMethod.GET)
	public ModelAndView getRole(@RequestParam("id") Long id) {
		Role role = roleService.getRole(id);
		ModelAndView mv = new ModelAndView();
		mv.setViewName("roleDetails");
		// 给数据模型添加一个角色对象
		mv.addObject("role", role);
		return mv;
	}
}

 O RoleService é injetado no código, para que você possa usar o ID do parâmetro passado para obter a função por meio dessa classe de serviço e, finalmente, adicionar a função consultada ao modelo e visualizar para uso futuro.

3. Ver renderização 

Em geral, o Spring MVC utilizará o JstlView para renderização por padrão, ou seja, vincula o modelo consultado ao modelo JSTL (JSP Standard Tag Library), para que o modelo de dados possa ser lido e exibido no JSP por meio do JSTL. No Spring MVC, há um grande número de visualizações disponíveis, para que você possa renderizar dados facilmente na visualização para responder às solicitações do usuário.

No código acima, é usado o nome da visualização roleDetails De acordo com a configuração, ele usará o arquivo /WEB-INF/jsp/roleDetail.jsp para responder, ou seja, gravar tags JSTL nesse arquivo para ler os dados do modelo. , Por exemplo:

<%@ page pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<title>out标签的使用</title>
</head>
<body>
</body>
<center>
	<table border="1">
		<tr>
			<td>标签</td>
			<td>值</td>
		</tr>
		<tr>
			<td>角色编号</td>
			<td><c:out value="${role.id}"></c:out></td>
		</tr>
		<tr>
			<td>角色名称</td>
			<td><c:out value="${role.roleName}"></c:out></td>
		</tr>
		<tr>
			<td>角色备注</td>
			<td><c:out value="${role.note}"></c:out></td>
		</tr>
	</table>
</center>
</html>

Na atual tecnologia front-end, a tecnologia Ajax é comumente usada.Nesses casos, muitas vezes o plano de fundo precisa retornar dados JSON para o front-end.Para isso, o Spring MVC também fornece um bom suporte para modelos e visualizações. O código de getRole é modificado para:

// 获取角色
@RequestMapping(value = "/getRole2", method = RequestMethod.GET)
public ModelAndView getRole2(@RequestParam("id") Long id) {
	Role role = roleService.getRole(id);
	ModelAndView mv = new ModelAndView();
	mv.addObject("role", role);
	// 指定视图类型
	mv.setView(new MappingJackson2JsonView());
	return mv;
}

O tipo de exibição no código é MappingJackson2JsonView, que requer o download do pacote Jackson2. Como essa é uma visualização JSON, o Spring MVC utilizará essa visualização para renderizar os resultados desejados. Portanto, obteremos os dados JSON necessários após a nossa solicitação e os forneceremos para a solicitação assíncrona do Ajax. Seu fluxo de execução é o seguinte:

Fluxo de dados JSON

Só que essa não é a única maneira de transformar o resultado em JSON. O uso da anotação @ResponeBody é um método mais simples e amplamente usado .

 

Publicado 281 artigos originais · elogiado 170 · 320.000 visualizações +

Acho que você gosta

Origin blog.csdn.net/ARPOSPF/article/details/105490945
Recomendado
Clasificación