Contenido:
- Introducción
- Creando un proyecto
- Conexión de resorte MVC
- Creando páginas y controlador
- Configuración
- Modelo
- Modelo-Vista-Controlador
Introducción
Comencé a familiarizarme con tecnologías y marcos que eran nuevos para mí estudiando varios ejemplos en los que se usaban, porque generalmente entiendo algo mejor cuando lo veo en acción usando un ejemplo de una aplicación completa. Normalmente, estos ejemplos son aplicaciones CRUD ( Crear , Leer , Actualizar , Eliminar ); Internet está lleno de ejemplos de este tipo de diversos grados de complejidad. El problema es que normalmente no explican en detalle cómo, qué y por qué se hizo allí, por qué se añadió tal o cual dependencia, por qué se necesita tal o cual clase, etc. En la mayoría de los casos, toman una aplicación completamente terminada, con un archivo POM final, con versiones finales de las clases, y simplemente repasan cada una, sin centrarse en las pequeñas cosas que probablemente parezcan obvias para una persona experimentada. He visto muchos ejemplos de este tipo y, por lo general, está claro cómo funciona todo, pero no está del todo claro cómo llegaron a esto. Por lo tanto, decidí que un ejemplo así sería útil no desde la posición de un desarrollador experimentado, sino desde la posición de un principiante que nunca ha trabajado con Spring, Hibernate y otras cosas.Creando un proyecto
Entonces, como soy un novato, no usaremos ningún arquetipo oscuro. Spring inicializr todavía suena demasiado aterrador. Por lo tanto, crearemos el proyecto Maven simple más común. No tengo un nombre de dominio, así que en groupid simplemente escribirétestgroup
y en artefactoid escribiré el nombre, por ejemplo filmography
(esta será una lista de películas). Creamos un proyecto y elegimos Enable auto-import
cuando la idea lo sugiere. Gracias a esto, cada vez que realicemos algún cambio en el archivo POM (Project Object Model, este archivo describe toda la estructura del proyecto Maven), inmediatamente todo se aplicará automáticamente al proyecto. Las bibliotecas se tomarán de nuestro repositorio local si ya las tenemos, o si usamos algunas dependencias nuevas que no hemos tratado antes, Maven simplemente las descargará a través de Internet desde el repositorio central. Maven también tiene una función para descargar fuentes y documentación (Descargar Fuentes y/o Documentación). También es muy conveniente, si algo no está claro con alguna clase o método, puedes ir al código fuente y ver cómo funciona todo por dentro. Agreguemos un par de detalles. Esta será una aplicación web y usaremos Tomcat . Para implementar una aplicación en Tomcat, debe transferirla allí en forma de archivo war (recurso de aplicación web, un formato especial para aplicaciones web). Para hacer esto, agregue la siguiente línea al archivo POM para que la aplicación se compile en un archivo war:
<packaging>war</packaging>
Bueno, también necesitarás un directorio especial para fuentes web, en nuestro caso habrá páginas jsp y algunos recursos web. Creemos un main
directorio webapp
. Debería llamarse exactamente así y ubicarse exactamente de main
la misma manera que java
, resources
porque esta es la estructura de directorios estándar de Maven. Una vez que hayamos instalado el paquete war
y así determinado que se trata de un proyecto web, automáticamente se marcará el directorio webapp
como fuentes de aplicaciones web (habrá un punto azul en él) y en esta carpeta se buscará todo lo relacionado con la web. Y un momento. De forma predeterminada, Maven usa la versión 1.5 del lenguaje, pero quiero usar, por ejemplo, la versión 1.8 - Java 8 (puede tomar 10 u 11, pero aún no hay planes para usar ninguna característica desde allí, así que sea 8). ). Esto se puede resolver de manera muy simple, escribimos en Google algo como "Maven java 8" y vemos qué se debe agregar al archivo POM para que Maven compile nuestras clases para la versión requerida. Como resultado, tenemos lo siguiente:
Conexión de resorte MVC
Tienes que empezar por algún lado. Según el plan, conectaremos la base de datos y usaremos Hibernación, pero todo esto suena demasiado aterrador por ahora. Primero debemos hacer algo más simple. Spring MVC, esto ya es mejor, conocemos el patrón MVC desde hace mucho tiempo, se usó en la mitad de las tareas grandes del curso. A partir de aquí empezaremos a bailar. Para crear una aplicación web con Spring MVC, también necesitamos una Servlet-API, es decir. aquello con cuya ayuda se llevará a cabo la interacción solicitud-respuesta. Intentemos conectar esto. Vamos a Google, buscamos las dependencias necesarias en el repositorio de Maven y las añadimos al archivopom.xml
. En la sección Bibliotecas externas puede ver que no solo se cargó spring-webmvc , sino también muchas otras cosas. Aquellos. No necesitamos incluir dependencias adicionales para Spring Core , Context , Beans , etc. que necesitamos, todo lo que necesitábamos se obtuvo junto con spring-webmvc .
Necesitamos hacer un pequeño descargo de responsabilidad. Por lo general, se recomienda agregar una dependencia por separado para cada biblioteca utilizada, incluso si ya están incluidas con las que ya se agregaron, porque esto puede ayudar a evitar algunos problemas y fallas. Un ejemplo sencillo. Digamos que agregamos una dependencia que usa alguna API y, al mismo tiempo, generaremos algún tipo de implementación para esta API. Y luego agregamos otra dependencia que usa la misma API y también recupera parte de su implementación para esto, pero esta vez es diferente. Así, tendremos 2 implementaciones diferentes de una misma API. Y si nosotros mismos queremos usar algunos métodos de esta API en alguna parte, entonces surgirá un problema, porque el sistema no sabrá qué implementación usar, elegirá al azar, quizás no la que esperábamos. Y si especifica explícitamente una dependencia para una de las implementaciones, se le dará prioridad. Sin embargo, esta no es una recomendación tan estricta; se aplica principalmente a proyectos grandes donde se utilizan muchas bibliotecas diferentes de diferentes empresas. No haremos eso aquí para no cargar demasiado el archivo POM; no se esperan problemas. Sin embargo, vale la pena tener esto en cuenta. |
provided
depender javax.servlet-api
? El alcance es el alcance de la dependencia, provided
lo que significa que la dependencia estará disponible en la etapa de compilación y prueba de la aplicación, pero no se archivará. El hecho es que para implementar la aplicación usaremos un contenedor de servlets, Tomcat, y ya tiene dichas bibliotecas en su interior, por lo que no es necesario transferirlas allí y cargar el archivo con una carga innecesaria. De cara al futuro, por la misma razón prescindiremos del método habitual main
, porque ya existe dentro de Tomcat.
Creando páginas y controlador
Intentemos preparar algo sencillo ahora. Primero, creemos unwebapp
directorio adicional, por ejemplo pages
, en el que se almacenarán nuestras vistas, es decir. páginas jsp y cree un par de páginas. Necesitaremos una página en la que en el futuro se mostrará una lista de películas, por ejemplo films.jsp
, y quizás podamos crear una página separada para editar, así sea editPage.jsp
. No los completaremos con nada serio por ahora; solo para probar, haremos un enlace de una página a otra. Ahora necesitamos una clase que procese solicitudes, es decir. controlador. Agreguemos un nuevo paquete controller
y creemos una clase en él FilmController
(en general, no es necesario empaquetar todo en diferentes paquetes, esta aplicación será muy pequeña y simple, pero en un proyecto normal puede haber muchos controladores, clases de configuración, modelos , etc., por lo que incluso empezando con proyectos pequeños, es mejor acostumbrarse inmediatamente a hacer todo de forma ordenada y estructurada para que no haya desorden). En esta clase crearemos métodos que devolverán nuestras vistas en respuesta a las solicitudes.
package testgroup.filmography.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class FilmController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView allFilms() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("films");
return modelAndView;
}
@RequestMapping(value = "/edit", method = RequestMethod.GET)
public ModelAndView editPage() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("editPage");
return modelAndView;
}
}
¿Cuál es el punto de? Spring MVC tiene algo llamado DispatcherServlet
. Es como el controlador principal, todas las solicitudes entrantes pasan a través de él y luego las pasa a un controlador específico. La anotación @Controller
simplemente le dice a Spring MVC que esta clase es un controlador (bueno, lógico en general), el despachador verificará las anotaciones @RequestMapping
para llamar al método apropiado. La anotación @RequestMapping
le permite establecer direcciones para los métodos del controlador, mediante las cuales estarán disponibles en el cliente (navegador). También se puede aplicar a la clase de controlador para establecer, por así decirlo, la dirección raíz de todos los métodos. allFilms()
El parámetro para el método value
está establecido en " /
", por lo que se llamará inmediatamente cuando se ingrese la combinación http://host:port/ en el navegador (es decir, de forma predeterminada es http://localhost:8080/ o http ://127.0.0.1:8080/ ). El parámetro method
especifica qué tipo de solicitud se admite (GET, POST, PUT, etc.). Como aquí solo recibimos datos, se utiliza GET. Más adelante, cuando aparezcan métodos para agregar y editar, ya habrá solicitudes POST. (Por cierto, en lugar de una anotación @RequestMapping
que indique un método, puede usar anotaciones @GetMapping
, @PostMapping
etc. @GetMapping
de manera equivalente @RequestMapping(method = RequestMethod.GET
)). En nuestros métodos, creamos un objeto ModelAndView
y configuramos el nombre de la vista que debe devolverse.
Configuración
Pasemos a configurar la configuración.config
Creemos una clase en el paquete WebConfig
. Tendrá un solo método que devuelve un objeto de tipo ViewResolver
, esta es la interfaz necesaria para encontrar una representación por nombre.
package testgroup.filmography.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "testgroup.filmography")
public class WebConfig {
@Bean
ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
@Configuration
le dice a Spring que esta clase es una clase de configuración y contiene las definiciones y dependencias bean
de los componentes. Los beans son objetos gestionados por Spring. La anotación se utiliza para definir un bean @Bean
. @EnableWebMvc
le permite importar la configuración de Spring MVC desde WebMvcConfigurationSupport
. También puedes implementar, por ejemplo, una interfaz WebMvcConfigurer
que tenga un montón de métodos y personalizar todo a tu gusto, pero no necesitamos entrar en eso todavía, la configuración estándar será suficiente. @ComponentScan
le dice a Spring dónde buscar los componentes que debe administrar, es decir clases marcadas con una anotación @Component
o sus derivados como @Controller
, @Repository
, @Service
. Estas anotaciones definen automáticamente la clase bean. En el método, viewResolver()
creamos su implementación y determinamos dónde buscar exactamente las representaciones webapp
. Por lo tanto, cuando en el método del controlador configuramos el nombre " films
" la vista se encontrará como " /pages/films.jsp
" Entonces, tenemos una clase de configuración, pero por ahora es solo algún tipo de clase separada, no afecta nuestra aplicación de ninguna manera. . Necesitamos registrar esta configuración en el contexto de Spring. Para esto necesitas una clase AbstractAnnotationConfigDispatcherServletInitializer
. En el paquete, config
creamos su sucesor, digamos AppInitializer , e implementamos sus métodos.
package testgroup.filmography.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
El último método registra direcciones y hay 2 métodos más para registrar clases de configuración. Las configuraciones web, donde ViewResolver
se definen 's y similares, se colocan en getServletConfigClasses()
. Es mejor leer sobre todo esto en la documentación y en varias guías, pero en nuestro caso no es necesario profundizar en esto todavía, el nuestro, WebConfig
en principio, se puede RootClasses
definir en ambos, incluso puedes definir ambos a la vez, seguirá funcionando. . Una cosa más. Puede haber problemas con la codificación cuando, al enviar valores con caracteres rusos desde el formulario, el resultado serán garabatos. Para resolver este problema, agregaremos un filtro que procesará previamente las solicitudes. Vamos a la clase AppInitializer y anulamos el método getServletFilters
en el que indicamos la codificación deseada, por supuesto, debe ser la misma que en todas partes, como en las páginas y en la base de datos:
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] {characterEncodingFilter};
}
Bueno, todo parece estar configurado, puedes intentar ejecutarlo y ver qué sucede. Ejecutar -> Ejecutar -> Editar configuraciones -> Agregar nueva configuración -> Servidor Tomcat -> Local A continuación, debe seleccionar un artefacto para implementar. La idea en sí dará una pista Advertencia: no hay artefactos marcados para implementación . Haga clic en el botón arreglar y seleccione ...: la guerra explotó . O puede ir a Implementación -> agregar -> Artefacto -> ...: la guerra explotó . Y también debe ir a Implementación y configurar el campo de contexto de Applecation (esto será parte de la dirección URL donde la aplicación estará disponible en el navegador) en " /
". Entonces nuestra aplicación estará disponible inmediatamente en http://localhost:8080/ (pero también puedes especificar algo allí, por ejemplo " /filmography
", y luego solo necesitarás agregar esto a todas las direcciones, es decir, por ejemplo no habrá " http://localhost:8080/edit" , pero será "http://localhost:8080/filmography/edit" ). Haga clic en Ejecutar y espere hasta que comience. Esto es lo que obtuve: todo parece estar bien, pero hay una advertencia. El hecho es que nuestras páginas ahora son de acceso público y se puede acceder a ellas directamente escribiendo la ruta en la barra de direcciones. Ingresamos a http://localhost:8080/pages/films.jsp y ahora hemos recibido nuestra página sin que el controlador lo sepa. De alguna manera esto no es muy correcto, así que crearemos un webapp
directorio especial WEB-INF
. Lo que hay dentro estará oculto al público y solo se podrá acceder a él a través de un controlador. Colocamos el directorio con nuestras vistas ( pages
) en WEB-INF
y, ViewResolver
en consecuencia, lo agregamos al prefijo:
viewResolver.setPrefix("/WEB-INF/pages/");
Ahora tenemos nuestra página en http://localhost:8080 , pero si intentamos ir directamente a http://localhost:8080/WEB-INF/pages/films.jsp obtenemos un error 404. Bueno, genial, tenemos el La aplicación web más sencilla, Hola mundo, como dicen. La estructura del proyecto actualmente se ve así:
Modelo
Ya tenemos vistas y un controlador, pero en MVC también hay una tercera letra, así que para completar el cuadro también agregaremos un modelo. En el paquete,model
creemos una clase Film
, por ejemplo, con los siguientes campos: int id
, String title
(título), int year
(año de estreno), String genre
(género) y boolean watched
(es decir, ya has visto esta película o no).
package testgroup.filmography.model;
public class Film {
private int id;
private String title;
private int year;
private String genre;
private boolean watched;
// + Getters and setters
}
Nada especial, solo una clase ordinaria, campos privados, captadores y definidores. Los objetos de tales clases también se denominan POJO
(objeto Java antiguo simple), bueno, es decir. "objeto java simple". Intentemos ahora crear dicho objeto y mostrarlo en la página. Por ahora, no nos preocuparemos demasiado por cómo crearlo e inicializarlo. Para probarlo, simplemente creémoslo estúpidamente directamente en el controlador, por ejemplo, así:
public class FilmController {
private static Film film;
static {
film = new Film();
film.setTitle("Inception");
film.setYear(2010);
film.setGenre("sci-fi");
film.setWatched(true);
}
Y agregue este objeto al nuestro ModelAndView
usando el método addObject
:
@RequestMapping(method = RequestMethod.GET)
public ModelAndView allFilms() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("films");
modelAndView.addObject("film", film);
return modelAndView;
}
Ahora podemos mostrar este objeto en nuestra página. En films.jsp
lugar de Hola Mundo escribiremos y aquí se sustituirá ${film}
el objeto correspondiente al nombre del atributo " ". film
Intentemos ejecutarlo y ver qué sucedió (para una salida clara del objeto, Film
se redefinió la clase toString()
):
Modelo-Vista-Controlador
En esta etapa, parece que ya tenemos una aplicación Spring MVC completa. Antes de continuar, sería bueno echar un vistazo a todo nuevamente y descubrir cómo funciona. En Internet puedes encontrar muchas fotos y diagramas sobre esto, a mí me gusta este:Dispatcher Servlet
, luego encuentra un controlador adecuado para procesar esta solicitud HandlerMapping
(esta es una interfaz para seleccionar un controlador, verifica cuál de los controladores disponibles tiene un método que acepta dicha dirección) , llama a un método adecuado y Controller
devuelve información sobre la vista, luego el despachador encuentra la vista deseada por nombre usando ViewResolver
'a, después de lo cual los datos del modelo se transfieren a esta vista y obtenemos nuestra página como salida. Algo como esto. Continuará... Presentamos Maven, Spring, MySQL, Hibernate y la primera aplicación CRUD (parte 1) Presentamos Maven, Spring, MySQL, Hibernate y la primera aplicación CRUD (parte 2) Presentamos Maven, Spring, MySQL, Hibernate y primera aplicación CRUD (parte 3) Introducción a Maven, Spring, MySQL, Hibernate y la primera aplicación CRUD (parte 4)
GO TO FULL VERSION