Spring实战第五章idea复现

本文记录了一位Spring初学者在搭建SpringMVC环境时遇到的问题,从创建Java工程,配置SpringMVC,编写控制器,传递模型数据到视图,处理表单以及使用校验器的过程。主要涉及IDEA、Tomcat、JDK版本选择,以及Spittr应用的控制器和视图交互,表单数据校验。
摘要由CSDN通过智能技术生成


前言

唉,第五章挺顺利,第六章利用Apache Tiles布局时不知道出了什么问题(百度是jdk版本问题——spring3.x需要jdk1.7,但我用的Spring4.0,所以没换jdk),哪怕回退操作也不能拯救一崩千里的工程 QQQAQQQ
甚是苦闷 QAQ
决定把每个操作都记下来
如果能对其他人有帮助就更好了~
– 框架小白,目前在Spring入门阶段(SpringMVC)


一、版本

  • idea 2021.2 商业版
  • jdk1.8
  • tomcat 9

大部分参考的

https://www.cnblogs.com/wormday/p/8435617.html
《Spring in action》Spring实战第四版

用tomcat10出过问题

二、新建工程

1.配置文件

新建了一个Java空工程,框架后期可以加,命名spittr_1,位置F:\SpringMVC_projects\spittr_1在这里插入图片描述
在这里插入图片描述
选择Add Framework Support…
选Java EE下的Web Application,Spring下的SpringMVC

配置tomcat,,,懒得写了,在Run —> Edit Configurations
配置完可能会有中文编码问题,回头出现了再改

在src下面新建包spittr

书上的web配置在Java类里写的,idea自动生成了XML配置文件,在/WEB-INF/web.xml,最后一项的 *.form 改成 /,即书上的将DispatcherServlet映射到“/”

在dispatcher-servlet.xml里,写上自动扫描组件的语句和jsp视图解析器(alt+enter真好用~):

<?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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="spittr"/>

    <!--指定视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 视图的路径 -->
        <property name="prefix" value="/WEB-INF/view/"/>
        <!-- 视图名称后缀  -->
        <property name="suffix" value=".jsp"/>
        <!-- Jstl -->
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
    </bean>
</beans>

注:Spittr是一个博客应用,主要有两个领域概念:Spitter(应用的用户)和Spittle(用户发布的状态)。

2.编写基本的控制器

@Controller定义了一个组件bean,当收到对“/”的HTTP GET请求时,就会调用home()方法,返回的”home”被解析为实际的视图——“/WEB-INF/views/home.jsp”的JSP。:

改一下,/会指向默认的index.jsp,将路由改成了/home

HomeController类文件:

package spittr.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.springframework.web.bind.annotation.RequestMethod.GET;

@Controller
@RequestMapping("/home")
public class HomeController {

    @RequestMapping(method = GET)
    public String home() {
        return "home";
    }

}


右键 - Add Framework Support…,选择Maven来管理依赖库,在pom.xml中添加:

    <dependencies>
        <!-- jstl 标签库  -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
            <scope>runtime</scope>
        </dependency>
        <!-- jsp 标准标签库 -->
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
    </dependencies>

点一下maven更新库:
在这里插入图片描述
基本每一次添加完库都要,File - Project Structure,(shift+ctrl+alt+s)选中图中位置右键,选第一个,这样库会被加到/WEB-INF/lib里
在这里插入图片描述
这是jstl需要引入的库,第六章会说
先新建一个/WEB-INF/resources/style.css,备用
在/WEB-INF/view下写home.jsp文件:
标红的是还没在控制器写的路由,不管它

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page session="false" %>
<html>
<head/>
<title>Spitter</title>
<link rel="stylesheet"
      type="text/css"
      href="<c:url value="/WEB-INF/resources/style.css" />" >
</head>
<body>
<h1>Welcome to Spittr!</h1>

<a href="<c:url value="/spittles" />">Spittles</a> |
<a href="<c:url value="/spitter/register" />">Register</a>

</body>
</html>

检查一下没有其他占8080端口的,理论上这个时候应该是可以跑的了。。。
在这里插入图片描述

项目结构:
在这里插入图片描述

3.传递模型数据到视图

需要有一个页面展现最近提交的Spittle列表
Spittle类:属性包括消息内容、时间戳、Spittle发布时的经纬度。。。

package spittr;


import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

import java.util.Date;

public class Spittle {
    private final Long id;
    private final String message;
    private final Date time;
    private double latitude;
    private double longitude;

    public Spittle(String message,Date time){
        this(message,time,null,null);
    }
    public Spittle(String message,Date time,Double latitude,Double longitude){
        this.id=null;
        this.message=message;
        this.time=time;
        this.latitude=latitude;
        this.longitude=longitude;
    }
    public long getId(){
        return id;
    }
    public String getMessage(){
        return message;
    }
    public Date getTime(){
        return time;
    }
    public Double getLongitude(){
        return longitude;
    }
    public Double getLatitude(){
        return latitude;
    }

    @Override
    public boolean equals(Object that){
        return EqualsBuilder.reflectionEquals(this,that,"id","time");
    }

    @Override
    public int hashCode(){
        return HashCodeBuilder.reflectionHashCode(this,"id","time");
    }


}

EqualsBuilder和HashCodeBuilder需要引入依赖:

        <!-- Equals -->
        <dependency>
            <groupId>org.apache.maven.surefire</groupId>
            <artifactId>surefire-booter</artifactId>
            <version>2.22.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>

还需要定义一个数据访问的Repository(实现部分应该是数据库相关内容,这里简单定义为接口)- SpittleRepository接口:

package spittr.data;

import spittr.Spittle;
import java.util.List;

public interface SpittleRepository {
    List<Spittle> findSpittles(long max, int count);
}

接口的实现放在SpittleRepositoryDAO类:

package spittr.data;

import org.springframework.stereotype.Repository;
import spittr.Spittle;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Repository
public class SpittleRepositoryDAO implements SpittleRepository {

    public SpittleRepositoryDAO() {

    }

    @Override
    public List<Spittle> findSpittles(long max, int count) {
        List<Spittle> spittles = new ArrayList<Spittle>();
        for (int i = 0; i < count; i++) {
            spittles.add(new Spittle("Spittle-" + i, new Date(),0.0,0.0));
        }
        return spittles;
    }
}

控制器SpittleController类:在模型中放入最新的spittle列表

package spittr.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import spittr.data.SpittleRepository;

@Controller
@RequestMapping("/spittles")
public class SpittleController {
    private SpittleRepository spittleRepository;

    @Autowired
    public SpittleController(SpittleRepository spittleRepository) { //注入SpittleRepository
        this.spittleRepository=spittleRepository;
    }

    @RequestMapping(method = RequestMethod.GET)
    public String spittles(Model model){
        model.addAttribute(spittleRepository.findSpittles(Long.MAX_VALUE,20));
        return "spittles";
    }
}

如果查看home.jsp会发现路由/spittles已经由标红变绿啦!
最后来一个呈现效果的spittles.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="s" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<html>
<head>
    <title>Spitter</title>
    <link rel="stylesheet" type="text/css" href="<c:url value="/WEB-INF/resources/style.css" />" >
</head>
<body>
<div class="spittleForm">
    <h1>Spit it out...</h1>
    <form method="POST" name="spittleForm">
        <input type="hidden" name="latitude">
        <input type="hidden" name="longitude">
        <textarea name="message" cols="80" rows="5"></textarea><br/>
        <input type="submit" value="Add" />
    </form>
</div>
<div class="listTitle">
    <h1>Recent Spittles</h1>
    <ul class="spittleList">
        <c:forEach items="${spittleList}" var="spittle" >
            <li id="spittle_<c:out value="spittle.id"/>">
                <div class="spittleMessage"><c:out value="${spittle.message}" /></div>
                <div>
                    <span class="spittleTime"><c:out value="${spittle.time}" /></span>
                    <span class="spittleLocation">(<c:out value="${spittle.latitude}" />, <c:out value="${spittle.longitude}" />)</span>
                </div>
            </li>
        </c:forEach>
    </ul>
    <c:if test="${fn:length(spittleList) gt 20}">
        <hr />
        <s:url value="/spittles?count=${nextCount}" var="more_url" />
        <a href="${more_url}">Show more</a>
    </c:if>
</div>
</body>
</html>

好吧,这个是我直接从源码复制的,看起来它比书上的内容多了一个表单提交,不管它。。。
在这里插入图片描述

4.处理表单

5.3接受请求的输入,包括:

  • 处理查询参数——要查看某一页Spittle列表
  • 处理路径参数——要根据给定的ID来展现一个特定的Spittle记录
    嗯试一试就行了不写了。。。进入5.4吧
    实现用户注册功能,即实现/spitter/register路由
    利用Spitter类来表示用户:
package spittr;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class Spitter {

    private Long id;
    private String username;
    private String password;
    private String firstName;
    private String lastName;
    private String email;

    public Spitter() {}

    public Spitter(String username, String password, String firstName, String lastName, String email) {
        this(null, username, password, firstName, lastName, email);
    }

    public Spitter(Long id, String username, String password, String firstName, String lastName, String email) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public boolean equals(Object that) {
        return EqualsBuilder.reflectionEquals(this, that, "firstName", "lastName", "username", "password", "email");
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this, "firstName", "lastName", "username", "password", "email");
    }

}


控制器SpitterController处理对/spitter/register的GET请求:

package spittr.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value = "/spitter")
public class SpitterController {

    @RequestMapping(value = "/register", method = RequestMethod.GET)
    public String showRegisterForm() {
        return "registerForm";
    }
}

写registerForm.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page session="false" %>
<html>
<head>
    <title>Spittr</title>
    <link rel="stylesheet" type="text/css" href="<c:url value="/WEB-INF/resources/style.css" />">
</head>
<body>
    <h1>Register</h1>
    <form method="post">
        First Name:<input type="text" name="firstName" /><br>
        Last Name:<input type="text" name="lastName" /><br>
        UserName:<input type="text" name="username" /><br>
        Password:<input type="password" name="password" /><br>
		<input type="submit" value="Register">
    </form>
</body>
</html>

这里form没有设置action属性,因此当表单提交时,它会提交到与展现时相同的URL路径上,即“/spitter/register”。这就意味着需要在服务器端处理该HTTP POST请求,因此在SpitterController中再添加一个方法来处理这个表单提交。
当处理注册表单的POST请求时,控制器接受表单数据并将其保存为Spitter对象,为了防止重复提交进行重定向到/spitter/username,重定向后显示个人的profile页面
SpitterController类中:

package spittr.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import spittr.Spitter;
import spittr.data.SpitterRepository;

@Controller
@RequestMapping(value = "/spitter")
public class SpitterController {

    private SpitterRepository spitterRepository;

    @Autowired
    public SpitterController(SpitterRepository spitterRepository){
        this.spitterRepository=spitterRepository;
    }

    @RequestMapping(value = "/register",method = RequestMethod.GET)
    public String showRegisterForm(){
        return "registerForm";
    }

    @RequestMapping(value = "/register",method = RequestMethod.POST)
    public String processRegisterForm(Spitter spitter){
        spitterRepository.save(spitter);
        return "redirect:/spitter/"+spitter.getUsername();
    }

    @RequestMapping(value = "/{username}",method = RequestMethod.GET)
    public String showSpitterProfile(
            @PathVariable("username") String username,
            Model model
    ){
        Spitter spitter=spitterRepository.findByUsername(username);
        model.addAttribute(spitter);
        return "profile";
    }
}

profile.jsp:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
  <title>Spittr</title>
  <link rel="stylesheet"
        type="text/css"
        href="<c:url value="/WEB-INF/resources/style.css" />" >
</head>
<body>
  <h1>Your Profile</h1>
  <c:out value="${spitter.username}" /><br/>
  <c:out value="${spitter.firstName}" />,
  <c:out value="${spitter.lastName}" />

</body>
</html>

提交表单之后,设想应该有一个将用户添加到数据库的处理,控制器中有SpitterRepository的接口,但是还没有实现它,这里以Map<Spitter,String>代替数据库了。。。
SpitterRepository接口:

package spittr.data;

import spittr.Spitter;

public interface SpitterRepository {
    void save(Spitter spitter);
    Spitter findByUsername(String username);
}

SpitterRepositoryDAO实现:

package spittr.data;

import org.springframework.stereotype.Repository;
import spittr.Spitter;
import java.util.HashMap;
import java.util.Map;

@Repository
public class SpitterRepositoryDAO implements SpitterRepository{
    public SpitterRepositoryDAO() {

    }

    Map<String,Spitter> spitterMap=new HashMap<>();

    @Override
    public void save(Spitter spitter){
        spitterMap.put(spitter.getUsername(),spitter);
        System.out.println("Save success");
    }

    @Override
    public Spitter findByUsername(String username){
        return spitterMap.get(username);
    }
}


5.校验器

校验表单:限制输入域值的长度,防止为空等
使用Spring对Java校验API(Java Validation API,又称JSR-303)的支持。
在Spitter类中,使用@NotNull和@Size注解:

    private Long id;

    @NotNull
    @Size(min=5, max=16)
    private String username;

    @NotNull
    @Size(min=5, max=25)
    private String password;

    @NotNull
    @Size(min=2, max=30)
    private String firstName;

    @NotNull
    @Size(min=2, max=30)
    private String lastName;

    @NotNull
    @Email
    private String email;

在pom.xml添加依赖:

    <!-- 校验器 -->
        <!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>

        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>el-api</artifactId>
            <version>2.2</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.1.0.Final</version>
        </dependency>

        <dependency>
            <groupId>org.jboss.logging</groupId>
            <artifactId>jboss-logging</artifactId>
            <version>3.3.2.Final</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml</groupId>
            <artifactId>classmate</artifactId>
            <version>1.3.3</version>
        </dependency>

在控制器中需要修改processRegisterForm()方法来应用校验功能:

    @RequestMapping(value = "/register",method = RequestMethod.POST)
    public String processRegisterForm(@Validated Spitter spitter, BindingResult result){ //校验Spitter输入
        if(result.hasErrors()){
            return "registerForm"; //如果校验出现错误,则重新返回表单
        }
        spitterRepository.save(spitter);
        return "redirect:/spitter/"+spitter.getUsername();
    }

理论上东西都实现完了。。。
一run定乾坤!
在这里插入图片描述
在这里插入图片描述
奈斯!
但是验证器没有起作用哈哈,第六章再说
溜了溜了

总结

下一章见!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值