当前端同一个html页面被后台不同的控制访问时,可能因为不同的控制器传的参数不同,导致报错,需要在可能没有传参数的参数上添加问号?
1、 前言
1.1 idae中spring boot项目使用thymeleaf模板,前端HTML页面获取后台Controller中的Model存放的数据
1.2 项目在登录后跳转到后台显示查询到数据库数据的页面(首先是还没有查询,需要进入页面后点击按钮才去查询并显示)
1.3 这里就直接报错误了,最开始我只能通过把查询到的数据显示到页面(就是刚刚登录成功,就跳转去查询数据)的方式解决错误,后面我发现一个好玩的方法,在这里介绍一下。
2、 错误信息
2.1主要错误
2021-11-20 20:40:36.536 ERROR 10352 — [nio-8082-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: “class path resource [templates/main.html]”)] with root cause
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field ‘records’ cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213) ~[spring-expression-5.3.12.jar:5.3.12]
2.2其他的小错误
The operator ‘SUBTRACT’ is not supported between objects of type ‘null’ and ‘java.lang.Integer’
SpelEvaluationException: EL1030E: The operator ‘ADD’ is not supported between objects of type ‘null’ and ‘java.lang.Integer’
3、 错误原因
3.1 前端页面通过 ${page.current} 获取后台Cotroller中查询的分页数据,获取失败。因为我最开始只是通过login请求登录成功了,并没有去查询数据,所以分页数据为空。
3.2 那个2.2中的小错误是我解决办法过程中产生出来的。那个错误其实就是相加或者相减过程中,不能是null和数字进行计算。这里使用的是三元运算符判断并赋默认值
((page?.current)==null?1:page.current)
<!--The operator 'SUBTRACT' is not supported between objects of type 'null' and 'java.lang.Integer'-->
<li th:class="${page?.current==1?'disable':''}" class="prev"><a aria-label="Previous" th:href="@{/showemp(pn=${((page?.current)==null?0:page.current)-1})}"><span aria-hidden="true">«</span></a></li>
<li th:class="${num==page?.current?'active':''}" th:each="num:${#numbers.sequence(1,((page?.current)==null?1:page.pages))}"><a th:href="@{/showemp(pn=${num})}">[[${num}]]</a></li>
<!--SpelEvaluationException: EL1030E: The operator 'ADD' is not supported between objects of type 'null' and 'java.lang.Integer'-->
<li th:class="${page?.current==page?.pages?'disable':''}" class="next"><a aria-label="Next" th:href="@{/showemp(pn=${((page?.current)==null?0:page.current)+1})}"><span aria-hidden="true">»</span></a></li>
4、 解决办法
4.1 添加问号,在每一个从后端获取的值中添加一个问号?
4.2 类似如下的page是后台model里面存放的分页数据
<a th:href="@{/delete/{id}(id=${book.id},pn=${page?.current})}" type="button" class="btn btn-danger btn-sm">删除</a>
<a th:href="@{/update/{id}(id=${book.id})}" type="button" class="btn btn-info btn-sm">更改</a></td>
Page<Book> page = new Page<>(pn,20);
Page<Book> bookPage = bookService.page(page, null);
model.addAttribute("page",bookPage);
5、 部分前端和后台代码
5.1 分页数据后台代码
@Controller
public class CrudController {
@Autowired
BookServiceImpl bookService;
@GetMapping("/showemp")
public String selectAll(@RequestParam(value = "pn",defaultValue = "1")Integer pn,
Model model){
Page<Book> page = new Page<>(pn,20);
Page<Book> bookPage = bookService.page(page, null);
model.addAttribute("page",bookPage);
// System.out.println(bookPage.getCurrent());
// System.out.println(bookPage.getRecords().size());
/**
* 2021-11-18 21:02:01.321 ERROR 9272 --- [nio-8082-exec-4] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8082-exec-4] Exception processing template "main": An error happened during template parsing (template: "class path resource [templates/main.html]")
*
* org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/main.html]")
* at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:241) ~[thymeleaf-3.0.12.RELEASE.jar:3.0.12.RELEASE]
* Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "page.getCurrent()" (template: "main" - line 86, col 17)
* 这里不能使用重定向:否则前端数据不能通过thymeleaf获取
*/
// return "redirect:/main";
return "main";
}
}
5.2 登录后台代码
@Controller
public class LoginController {
@Autowired
BookServiceImpl bookService;
@GetMapping("/login")
public String toLoginPage(){
return "login";
}
@PostMapping("/login")
public String LoginValidation(Book book,
RedirectAttributes redirectAttributes,
Model model,
HttpSession session){
String name = book.getName();
String password = book.getPassword();
Map<String,Object> map = new HashMap<>();
map.put("name",name);
map.put("password",password);
QueryWrapper<Book> queryWrapper = new QueryWrapper<>();
queryWrapper.ge("name",name );
queryWrapper.ge("password",password);
Book one = bookService.getOne(queryWrapper);
// if (one.toString()!=null){
if (one!=null){
// if (!StringUtils.isEmpty(one.toString())){
/**
* org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'records' cannot be found on null
* 如果直接从登录界面进入这个页面是错误的,因为这里用到了showemp这个请求的page分页查询的数据,直接进入是没有查询的,page分页数据为null
* 所以只能先发送showemp请求查询到page分页数据才能成功的到达main页面。
*/
// return "redirect:/main";
session.setAttribute("login",name);
//模拟服务器错误:5xx.html测试
// int a = 12/0;
// return "redirect:/showemp";
return "redirect:/main";
}
String msg = "账号或密码错误";
model.addAttribute("msg",msg);
return "login";
}
}
5.3 前端显示分页数据的HTML页面(最开始登录没有显示,需要点击 显示按钮)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<title>员工信息显示</title>
<link rel="canonical" href="https://getbootstrap.com/docs/4.0/examples/dashboard/">
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--员工数据表格显示-->
<div class="container table-responsive" style="margin-top: 50px">
<table class="table table-bordered">
<caption class="caption"><a th:href="@{/showemp}">显示员工信息</a> | <a th:href="@{/add}">添加</a></caption>
<thead>
<tr>
<th>序号</th>
<th>ID</th>
<th>Name</th>
<th>Password</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="book,statu:${page?.records}">
<th>[[${statu.count}]]</th>
<td th:text="${book.id}"></td>
<td>[[${book.name}]]</td>
<td>[[${book.password}]]</td>
<td>
<a th:href="@{/delete/{id}(id=${book.id},pn=${page?.current})}" type="button" class="btn btn-danger btn-sm">删除</a>
<a th:href="@{/update/{id}(id=${book.id},pn=${page?.current})}" type="button" class="btn btn-info btn-sm">更改</a>
</td>
</tr>
</tbody>
</table>
<div class="row-fluid">
<div class="span6">
<div>当前第 [[${page?.current}]] 页 总计 [[${page?.pages}]] 页 共 [[${page?.total}]] 条记录</div>
</div>
<div class="span6">
<nav aria-label="Page navigation">
<ul class="pagination">
<!--The operator 'SUBTRACT' is not supported between objects of type 'null' and 'java.lang.Integer'-->
<li th:class="${page?.current==1?'disable':''}" class="prev"><a aria-label="Previous" th:href="@{/showemp(pn=${((page?.current)==null?0:page.current)-1})}"><span aria-hidden="true">«</span></a></li>
<li th:class="${num==page?.current?'active':''}" th:each="num:${#numbers.sequence(1,((page?.current)==null?1:page.current))}"><a th:href="@{/showemp(pn=${num})}">[[${num}]]</a></li>
<!--SpelEvaluationException: EL1030E: The operator 'ADD' is not supported between objects of type 'null' and 'java.lang.Integer'-->
<li th:class="${page?.current==page?.pages?'disable':''}" class="next"><a aria-label="Next" th:href="@{/showemp(pn=${((page?.current)==null?0:page.current)+1})}"><span aria-hidden="true">»</span></a></li>
</ul>
</nav>
</div>
</div>
</div>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<!-- <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script> -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
</body>
</html>