这几个问题,干扰了我很长时间。
主要因为书本的例子,是通过controller层返回到jsp层。但是,最后一个SSM项目,它用的是controller返回信息给Service层,再由Service层返回Jsp层。
实训:编写一个模糊查询姓名的项目。在另一个show.jsp页面显示查询信息。
一步一步:
先通过controller层返回到JSP层。
第一个问题:(未找到迭代器,或者不是迭代器类型)
javax.servlet.ServletException: javax.servlet.jsp.JspTagException: Don't know how to iterate over supplied "items" in <forEach>
show.jsp对应的代码信息:
<%--querylist.account是有提示的。只有list.account没有提示。(说明list不是一个可迭代器对象)--%> <c:forEach items="${queryList}" var="user"> ${user.account}<br> ${user.password}<br> ${user.sex}<br> ${user.name}<br> </c:forEach>
这是show.jsp对应的代码,这个信息表示querylist的遍历器没有这个对象。说明,存在的问题是querylist不是一个可迭代的对象。我们返回到定义这个queryList的Controller文件,发现:
// 问题出在user这里,queryList是一个集合对象,但是user是一个类对象,是用不了c:foreach model.addAttribute("queryList",user);
解决方式:将user更换成一个迭代器对象。(例如,前面我们定义的service层的方法是一个list类型,这就是一个迭代器对象。)(额外:在使用 Service层作为与JSP返回的层级时,怀疑之前一直报错的原因,就是Service层的返回类型被我换成了String类型)
修改之后,可以在show.jsp显示用户查询信息。
第二个问题:未找到bean “query2”。明明定义了query2
我尝试将用户信息查询得到的信息放在query.jsp页面下面,也就是query.jsp提供查询功能,并将信息放在query.jsp的下面。
一开始我的尝试:就是将原本返回给show的方法,改为返回未query。
在query.jsp里面,将show.jsp的代码复制过来。但是,结果出现一个很大的问题,我找了很久才发现问题:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'query2' available as request attribute
这个错误信息表明在处理请求时,Spring无法找到名为query2
的bean。
JSP原本的代码是:(这里需要将query修改为input)
<form:form method="post" action="${pageContext.request.contextPath}/user/query" modelAttribute="query2">
因为,我们将查询和显示,在Controller分别用了两个方法表示,大概流程是这样的:
首先我们在浏览器输入/input。
/input里面返回POJO的信息给query.jsp 。通过query2的属性,将POJO和query.jsp的表单信息进行绑定。
接着在query.jsp里面,提交用户信息,action 为/query 。
/query里面返回从数据库获取的信息给query.jsp。但是,此时query.jsp里面,又会读取一次表单信息,而此时表单信息的属性query2并没有定义。于是,IDEA就提示报错,:找不到bean “query2”。
修改之后:
大概流程:
首先浏览器输入/input 。
它返回POJO的信息给query.jsp。注意此时POJO还没有和query.jsp的name进行绑定。所以数据库返回的数据此时为null。
它也返回数据库获取的数据给query.jsp。
在用户query.jsp,它提交action 为/input。
于是和上面的信息一样。
最后返回给query.jsp。此时,jsp里面的querylist就存在信息了。
第三个问题:测试 跟踪流程去发现问题 (挺重要的)
(学习这个方式,以后就不需要先对spring和Mybatis先进行整合并测试。)我想通过一些测试方法跟踪 这个流程的输出情况。通过查找资料,得出,可以通过日志方式输出。
方法:引入`org.slf4j.Logger`类
不是`org.apache.commons.logging.Log`类`。Log`类的`info`方法只接受一个参数,不能使用占位符`{}`来格式化消息。(在前面,我学过使用org.apache.commons.logging.Log`类,使用打印像logger.info("登录成功") 这样的信息)如果想要使用占位符来格式化消息,您可以将`Log`类更改为`org.slf4j.Logger`类,并使用`org.slf4j.LoggerFactory`来获取日志记录器(logger)对象。例如,您可以将代码修改为以下内容:
其实就是在controller类里面添加两句:
private static final Logger logger = LoggerFactory.getLogger(Query2Controller.class);
logger.info("User info: {}", user); //测试user对象是否获取到数据。
//如果还想测试queryList是否获取数据,也可以这样写。
package controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 po.User;
import service.Query2;
@Controller
@RequestMapping("/user")
public class Query2Controller {
private static final Logger logger = LoggerFactory.getLogger(Query2Controller.class);
@Autowired
private Query2 query2;
@RequestMapping("/input")
public String input(Model model, User user){
logger.info("User info: {}", user);
model.addAttribute("query2",user);
model.addAttribute("queryList",query2.query2list(user));
return "query";
}
}
在添加方法之前,需要把有关依赖包导入进来。
又因为我们的项目是通过log4j的那个配置,文件输出日志信息,所以,需要对SLF4J和log4j进行绑定。
就两个依赖包:一个SLF4j的依赖包,和前面的输出日志信息搭配。
一个是绑定log4j的依赖包。实现在log4j的配置文件里面输出日志信息。
使用`log4j`作为日志记录实现,您需要在应用程序的类路径中添加`SLF4J`到`log4j`的绑定库。您可以通过添加以下依赖项来实现这一点:
<!-- for Maven -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.32</version>
</dependency>
此外,您还需要在应用程序的类路径中添加`log4j`库。您可以通过添加以下依赖项来实现这一点:
<!-- for Maven -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
最后,配置log4j的配置文件,
不过,这个文件,其实在创建项目的时候,在mybatis的学习里面,我们已经添加过了。
添加完依赖项后,您需要配置`log4j`以指定日志记录行为。您可以在应用程序的类路径中创建一个名为`log4j.properties`的文件,并在其中指定日志记录配置。例如,您可以在配置文件中添加以下内容:
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
在上面的示例中,我们配置了一个名为`stdout`的控制台日志记录器(appender),它将日志信息输出到控制台。您可以根据需要更改配置。
结果如下:
user info 这个的信息,就是我们获取的user对象信息。
通过控制台信息,我们再来分析:
这整个流程:
首先浏览器输入:/user/input 。进入input界面。
返回POJO信息