回顾
前面我们已经搭建好了一个基于 Maven 的最基本的Spring以及Spring MVC 环境。
接下来,我们就在这个环境下来 “布置” 出我们最基本的控制器。
请求处理的位置
- 我们熟悉最简单的一个控制器应该是这样的:
package com.twm.bookmvc;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MyController {
@RequestMapping("/my")
public String hello() {
return "mypage";
}
}
在指定的文件夹先写页面,然后前端直接输入:http://localhost:8888/bookmvc/my
- 现在我们把映射注解 @RequestMapping 同时放在类和方法上:
@Controller
@RequestMapping("my")
public class MyController {
@RequestMapping("/page1")
public String hello() {
return "mypage";
}
}
这样写,首先映射先找到类这一级,然后再在这个类的所有方法里去匹配。
可想而知,这样做的好处:可以抽象的把相似的方法放在同一个类里面,可以更好的理解请求的层次,也避免了写 url 映射的重复。
- 此外,我们还应注意到 @RequestMapping( { "/page1" , "/page2" } ) 还可以多对一答应映射。
暂时不考虑数据库的连接,我们需要先模拟数据资源
我们定义一个书库,书库里放着很多的书:
- 为了实现松耦合,我们先为书库定义一个接口:
public interface BookStore {
// 返回的最大序号,往前数共要 count 本
List<Book> buySomeBooks(int idMax, int count);
}
- 实现这个接口:
public class BookStoreImpl implements BookStore {
private List<Book> books;
private int all;
// 初始化书库书籍的总量
public BookStoreImpl(int all){
this.all = all;// 这句千万不要忘记加
System.out.println("创建时数组的长度设定:"+all);
List<Book> books = new ArrayList<>();
this.books=books;// 这句话也不要忘记
for (int i=0; i<all; i++){
this.books.add(i,new Book(i,"第"+i+"本书"));
}
System.out.println("第四本书信息:"+ books.get(4).getMessage());
}
@Override// 实现返回所需书的数量
public List<Book> buySomeBooks(int idMax, int count) {
System.out.println(count+" :::: " +all);
if (count<all){
System.out.println("返回书库的总量");
System.out.println("截取 : " +(idMax-count)+" : "+idMax);
return this.books.subList(idMax-count,idMax);
}
else{
System.out.println("else");
return null;
}
}
}
- 编写书实体类
public class Book {
private long id;
private String message;
public Book() {
}
public Book(long id, String message) {
this.id = id;
this.message = message;
}
public long getId() {
return id;
}
public String getMessage() {
return message;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book)) return false;
Book book = (Book) o;
return getId() == book.getId() &&
getMessage().equals(book.getMessage());
}
@Override
public int hashCode() {
return Objects.hash(getId(), getMessage());
}
}
- 将上面两个组件都加入 IOC 容器
<bean id="Book" class="com.twm.bookmvc.dto.Book">
<constructor-arg value="1"></constructor-arg>
<constructor-arg value="book"></constructor-arg>
</bean>
<bean id="BookStoreImpl" class="com.twm.bookmvc.BookStore.impl.BookStoreImpl">
<constructor-arg value="60" type="int"></constructor-arg>
</bean>
传递模型数据到视图(后端数据前传)
@Controller
@RequestMapping("my")
public class MyController {
// 声明书库 注入 书库
@Autowired
private BookStore bookStore;
@RequestMapping("/buyBooks")
public String buyBooks(Model model) { // 加入模型
// 把数据加入模型属性
model.addAttribute("books",
bookStore.buySomeBooks(50,20)
);
System.out.println(bookStore.buySomeBooks(50,20));
return "buybooks";
}
- 编写前端输入 url 展示传送数据信息的 jsp:
<%@ page isELIgnored="false" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>买书</title>
</head>
<body>
<h1>买到书了吗?</h1>
........................................<br>
<c:forEach items="${books}" var="books">
<c:out value="${books.message}"/>
<c:out value="${books.id}"/>
</c:forEach>
</body>
</html>
- 测试数据资源是否可用:
处理带有请求数据的控制器编写
方式一:请求参数法形如: url ? a=10&b=20
- 编写前端jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>分页</title>
</head>
<body>
<h1>分页</h1>
<form action="../my/showpage">
第<input type="text" name="where" value=${where}>页
<br>
每页显示<input name="everyn" type="text" value=${every}>条
<input type="submit" value="跳转">
</form>
共${total}页
<br>显示<br>
<c:forEach items="${now}" var="now">
<li> <c:out value="${now.message}"/></li>
<li> <c:out value="${now.id}"/></li>
</c:forEach>
</body>
</html>
显示效果如下,前端会传入 第几页,每页显示几条 这两个参数
- 写出请求控制器的处理方法
// 查询参数 请求 按前端要求返回数据
@RequestMapping("/showpage")
public String showpage(
@RequestParam(value = "where",defaultValue ="1") int where,
@RequestParam(value = "everyn",defaultValue ="10") int every,
Model model){
System.out.println("进入请求——————");
model.addAttribute("now",bookStore.showBooks
(where*every-every, where*every
));
model.addAttribute("total",bookStore.total());
model.addAttribute("where",where);
model.addAttribute("every",every);
return "splitPage";
}
- 补充请求页面的接口,补充实现
// 返回书的总量
int total();
// 分页返回的接口
List<Book> showBooks(int start, int end);
@Override// 实现返回所需书的数量
public List<Book> showBooks(int start, int end) {
if (end<all){
System.out.println("返回书库的总量");
System.out.println("截取 ");
return this.books.subList(start,end);
}
else{
System.out.println("else");
return null;
}
}
@Override
public int total(){
return all;
}
这里需要注意的是,url 路径不要写错,还有需要确保前后端接口处 名称一定要一致。
方式二:路径参数接收输入 形如:url /1234
这种方法最适合资源的请求方式,因为对于资源来说,我们更习惯用 / 而不是 ?来表达,用于定位单一资源。
- 编写控制器方法:
// 路径参数参数 请求 按前端要求返回数据
@RequestMapping(value = "/{seekone}") // 占位符允许路径作为参数传入
public String seekone(
@PathVariable("seekone") int id,
Model model){
model.addAttribute("one",bookStore.seekOne(id));
model.addAttribute("total",bookStore.total());
return "one";}
- 补充接口,补充实现
// 查找单个资源
Book seekOne(int id);
@Override
public Book seekOne(int id){
return this.books.get(id);
}
- 编写jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>查找单个信息</h1>
请不要输入超过${total}的数字
<form action="../my/5">
您查询书的id是: <input id="id" type="text">
<input type="submit" value="提交">
</form>
==============显示区==================<br>
书的id是${one.id}
书的消息${one.message}
</body>
</html>
注意这里我不知道怎么把id通过输入框加进 url 所以,只能手动的改 action="../my/6"去修改id了.......
- 测试
完成。