Thymeleaf意外和奇怪的类投射异常在视图中

时间:2015-07-29 02:37:22

标签: spring spring-mvc spring-boot thymeleaf classcastexception

更新:

下面的编辑#2显示了此问题的临时解决方案,但提出了一个新问题

我正在使用Spring MVC和Thymeleaf开发一个客户端。

我有两个用户,一个基本用户和一个管理员。当基本用户登录时,他的个人信息将显示在他的主页上。当管理员登录时,他可以执行各种搜索操作以在后端数据库(MongoDB)中查找用户。他可以通过州,城市,用户名等找到....

我在客户端执行特定的操作序列后才收到此错误:java.lang.ClassCastException: formBeans.User cannot be cast to java.util.Map

  1. 以管理员身份登录
  2. 搜索所有用户
  3. 退出
  4. 以基本用户身份重新登录
  5. 抛出以上错误
  6. 就像我说的,当基本用户登录时,应该显示他的个人信息。以基本用户身份登录可以在其他时间登录,但在此特定情况下则不行。但是,在我可能没有遇到的其他情况下可能会发生此错误。

    这是我的用户模型和表单支持bean类:

    package formBeans;
    
    import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
    
    @JsonIgnoreProperties(ignoreUnknown = true)
    public class User {
    
        private String firstname;
        private String lastname;
        private String username;
        private String password;
        private String phoneNumber;
        private String email;
        private String address;
        private String city;
        private String state;
        private String zipCode;
    
        public String getFirstname() {
            return firstname;
        }
        public String getLastname() {
            return lastname;
        }
        public String getUsername() {
            return username;
        }
        public String getPassword() {
            return password;
        }
        public String getPhoneNumber() {
            return phoneNumber;
        }
        public String getEmail() {
            return email;
        }
        public String getAddress() {
            return address;
        }
        public String getCity() {
            return city;
        }
        public String getState() {
            return state;
        }
        public String getZipCode() {
            return zipCode;
        }
        public void setFirstname(String firstname) {
            this.firstname = format(firstname);
        }
        public void setLastname(String lastname) {
            this.lastname = format(lastname);
        }
        public void setUsername(String username) {
            this.username = format(username);
        }
        public void setPassword(String password) {
            this.password = password;
        }
        public void setPhoneNumber(String phoneNumber) {
            this.phoneNumber = phoneNumber;
        }
        public void setEmail(String email) {
            this.email = format(email);
        }
        public void setAddress(String address) {
            this.address = format(address);
        }
        public void setCity(String city) {
            this.city = format(city);
        }
        public void setState(String state) {
            this.state = format(state);
        }
        public void setZipCode(String zipCode) {
            this.zipCode = zipCode;
        }
    
        public String format(String data) {
            String firstLetter = data.substring(0, 1).toUpperCase();
            String restLetters = data.substring(1).toLowerCase();
            return firstLetter + restLetters;
        }
    }
    

    以下是基本用户的主页:

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml"
        xmlns:th="http://www.thymeleaf.org"
        xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
    <head>
    <title>Home</title>
    <link rel="stylesheet" th:href="@{/css/topcoat-desktop-light.min.css}" href="../../css/topcoat-desktop-light.min.css"/>
    </head>
    <body>
    <div th:include="fragment :: header"></div>   
        <h1>Welcome, <span th:text="${credentials.username}"></span> </h1>
    
        <h2>My profile:</h2>
        <a th:href="@{/edit}">Edit my profile</a>
        <br></br>
        <br></br>
            <table>
                <tr><td>Firstname:</td> <td th:text="${user.firstname}"></td></tr>
                <tr><td>Lastname:</td> <td th:text="${user.lastname}"></td></tr>
                <tr><td>Username:</td> <td th:text="${user.username}"></td></tr>
                <tr><td>Address:</td> <td th:text="${user.address}"></td></tr>
                <tr><td>City:</td> <td th:text="${user.city}"></td></tr>
                <tr><td>State:</td> <td th:text="${user.state}"></td></tr>
                <tr><td>Zip code:</td> <td th:text="${user.zipCode}"></td></tr>
                <tr><td>Email:</td> <td th:text="${user.email}"></td></tr>
                <tr><td>Phone number:</td> <td th:text="${user.phoneNumber}"></td></tr>
                <tr><td><hr></hr></td></tr>
            </table>
    </body>
    </html>
    

    正如您在html页面中看到的那样,有时Thymeleaf无法识别&#34;用户&#34;宾语。

    有什么想法吗?

    编辑:感谢您的回复。以下是一些更相关的代码:

    堆栈跟踪:堆栈跟踪不会在我的视图或任何Java类中的特定行号上给出任何错误。这似乎是Spring的Java文档中的内部错误。

    java.lang.ClassCastException: formBeans.User cannot be cast to java.util.Map
        at org.springframework.context.expression.MapAccessor.read(MapAccessor.java:49)
        at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:188)
        at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:94)
        at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:46)
        at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:375)
        at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:88)
        at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:120)
        at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:267)
        at org.thymeleaf.spring4.expression.SpelVariableExpressionEvaluator.evaluate(SpelVariableExpressionEvaluator.java:139)
        at org.thymeleaf.standard.expression.VariableExpression.executeVariable(VariableExpression.java:154)
        at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:59)
        at org.thymeleaf.standard.expression.Expression.execute(Expression.java:103)
        at org.thymeleaf.standard.expression.Expression.execute(Expression.java:133)
        at org.thymeleaf.standard.expression.Expression.execute(Expression.java:120)
        at org.thymeleaf.standard.processor.attr.AbstractStandardTextChildModifierAttrProcessor.getText(AbstractStandardTextChildModifierAttrProcessor.java:68)
        at org.thymeleaf.processor.attr.AbstractTextChildModifierAttrProcessor.getModifiedChildren(AbstractTextChildModifierAttrProcessor.java:59)
        at org.thymeleaf.processor.attr.AbstractChildrenModifierAttrProcessor.processAttribute(AbstractChildrenModifierAttrProcessor.java:59)
        at org.thymeleaf.processor.attr.AbstractAttrProcessor.doProcess(AbstractAttrProcessor.java:87)
        at org.thymeleaf.processor.AbstractProcessor.process(AbstractProcessor.java:212)
        at org.thymeleaf.dom.Node.applyNextProcessor(Node.java:1017)
        at org.thymeleaf.dom.Node.processNode(Node.java:972)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.NestableNode.computeNextChild(NestableNode.java:695)
        at org.thymeleaf.dom.NestableNode.doAdditionalProcess(NestableNode.java:668)
        at org.thymeleaf.dom.Node.processNode(Node.java:990)
        at org.thymeleaf.dom.Document.process(Document.java:93)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1155)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1060)
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1011)
        at org.thymeleaf.spring4.view.ThymeleafView.renderFragment(ThymeleafView.java:335)
        at org.thymeleaf.spring4.view.ThymeleafView.render(ThymeleafView.java:190)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1244)
        at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1027)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:971)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
    

    &#34;用户&#34;对象存储为会话对象。以下是控制器的一些相关代码:

       /* Here are my session attributes */
        @Controller
        @SessionAttributes({ "credentials", "user" })
        public class ViewController implements ErrorController {
    
        /* Here is the login function. If the user is a basic user, it redirects him to /getBasicUser.*/
            @RequestMapping(value = "/login", method = RequestMethod.POST)
            public String login(@ModelAttribute("credentials") Credentials credentials,
                    RedirectAttributes redirect) {
    
                RestTemplate restTemplate = new RestTemplate();
                RoleInfo roleInfo = restTemplate.postForObject(
                        "http://localhost:8080/users/login", credentials,
                        RoleInfo.class);
    
                if (roleInfo != null) {
                    if (roleInfo.isAdmin()) {
                        return "redirect:/adminHome";
                    } else {
                        redirect.addFlashAttribute("credentials", credentials);
                        return "redirect:/getBasicUser";
                    }
                } else {
                    return "login_fail";
                }
            }
    
    /* This function GETs the basic user from the back-end (MongoDB) repository and stores it as a session object in the model using redirect.addFlashAttribute("user", user);*/
    @RequestMapping(value = "/getBasicUser", method = RequestMethod.GET)
        public <T> String getBasicUser(
                @ModelAttribute("credentials") Credentials credentials,
                Model model, RedirectAttributes redirect) {
    
            RestTemplate restTemplate = new RestTemplate();
            String url = "http://localhost:8080/users/getBasicUser?username="
                    + credentials.getUsername();
            ResponseEntity<User> responseEntity = restTemplate.exchange(
                    url,
                    HttpMethod.GET,
                    new HttpEntity<T>(createHeaders(credentials.getUsername(),
                            credentials.getPassword())), User.class);
            User user;
            user = responseEntity.getBody();
    
            if (user != null) {
                redirect.addFlashAttribute("user", user);
                System.out.println("username: " + user.getUsername());
                return "redirect:/basicHome";
            } else {
                return "register_fail";
            }
        }
    
        /* This is the method that returns the home page. If you look at the getBasicUser() method above, it redirects it to this home page */
        @RequestMapping(value = "/basicHome", method = RequestMethod.GET)
            public String getBasicHomePage() {
                return "basic_home";
            }
    

    编辑#2:根据https://github.com/thymeleaf/thymeleaf/issues/357,当我将${user['firstname']}, ${user['lastname']},....等而不是${user.firstname}, ${user.lastname},...等添加到我的basicHome.html页面时,此问题不再坚持。

    我实现这个的原始方式是使用Thymeleaf表达式语言,而新的,解决的方式是Spring Expression Language。 Spring似乎将对象的键值对存储为地图,并且这种新方式直接访问地图的键值对。因此,访问用户[&#39;名字&#39;]将等于&#34; Bob&#34;。

    但现在问题仍然存在,为什么它不能将User对象转换为map,以便我可以使用$ {user.key}来访问这些值?

1 个答案:

答案 0 :(得分:0)

从百里香2更新到3时,我遇到了同样的问题。问题是,我们有一些代码将“字段符号”用于非字段用途。

例如,我们有:

th:if="*{someProperty}"

代替:

th:if="${bean.someProperty}"

我只需要对几个表格进行简单的修复,我们就很好了。