最近再做一个开源项目的时候,用到了thymeleaf作为模板引擎,自动生成页面的时候,一直在报错,下面贴出错误提示代码

exception

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "ServletContext resource [/WEB-INF/templates/item/createPage.html]")
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
	org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
root cause

org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "ServletContext resource [/WEB-INF/templates/item/createPage.html]")
	org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:235)
	org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100)
	org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:649)
	org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
	org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072)
	org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:362)
	org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:189)
	org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1325)
	org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1069)
	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1008)
	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
	org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
root cause

java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/templates/item/createPage.html]
	org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:159)
	org.thymeleaf.spring5.templateresource.SpringResourceTemplateResource.reader(SpringResourceTemplateResource.java:103)
	org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:223)
	org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100)
	org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:649)
	org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
	org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072)
	org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:362)
	org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:189)
	org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1325)
	org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1069)
	org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1008)
	org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
	org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
	org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
	org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

对应的controller为:


@Controller
@RequestMapping("/item")
public class ItemController {

    @Value("${pagePath}")
    private String pagePath;

    @Reference
    private SpuService spuService;

    @Autowired
    private TemplateEngine engine;

    @Reference
    private CategoryService categoryService;


    /**
     * 通过获取spuId来创建页面
     * @param id
     */
    @GetMapping("/createPage")
    public void createPage(String id){

        Goods goods=spuService.findGoodsById(id);

        Spu spu = goods.getSpu();

        List<Sku> skuList = goods.getSkuList();


        List<String> categories=new ArrayList<>();
        categories.add(  categoryService.findById(spu.getCategory1Id()).getName() );//一级分类
        categories.add(  categoryService.findById(spu.getCategory2Id()).getName() );//二级分类
        categories.add(  categoryService.findById(spu.getCategory3Id()).getName() );//三级分类
        //sku页面url集合  以sku的spec的json数据为键值 skuId为url
        //sku地址列表
        Map<String,String> urlMap=new HashMap<>();
        for(Sku sku:skuList){
            if("1".equals(sku.getStatus())){
                String specJson = JSON.toJSONString( JSON.parseObject(sku.getSpec()), SerializerFeature.MapSortField);
                urlMap.put(specJson,sku.getId()+".html");
            }
        }
        //System.out.println("urls = " + urls);
//        //System.out.println("goods = " + goods);
        //每个sku生成一个一个页面
        for(Sku sku:skuList){
            //(1) 创建上下文和数据模型
            Context context=new Context();
            Map<String,Object> dataModel= new HashMap<>();
            dataModel.put("spu",spu);
            dataModel.put("sku",sku);
            dataModel.put("categoryList",categories);
            dataModel.put("skuImages", sku.getImages().split(",") );//sku图片列表
            dataModel.put("spuImages", spu.getImages().split(",") );//spu图片列表

            Map paraItems=   JSON.parseObject( spu.getParaItems());//参数列表
            dataModel.put("paraItems",paraItems);
            Map<String,String> specItems = (Map)JSON.parseObject(sku.getSpec());//规格列表  当前sku
            dataModel.put("specItems",specItems);

            //{"颜色":["天空之境","珠光贝母"],"内存":["8GB+64GB","8GB+128GB","8GB+256GB"]}
            //{"颜色":[{ 'option':'天空之境',checked:true },{ 'option':'珠光贝母',checked:false }],.....}
            Map<String,List> specMap =  (Map)JSON.parseObject(spu.getSpecItems());//规格和规格选项
            for(String key :specMap.keySet()  ){  //循环规格
                List<String> list = specMap.get(key);//["天空之境","珠光贝母"]
                List<Map> mapList=new ArrayList<>();//新的集合  //[{ 'option':'天空之境',checked:true },{ 'option':'珠光贝母',checked:false }]
                //循环规格选项
                for(String value:list){
                    Map map=new HashMap();
                    map.put("option",value);//规格选项
                    if(specItems.get(key).equals(value) ){  // 如果和当前sku的规格相同,就是选中
                        map.put("checked",true);//是否选中
                    }else{
                        map.put("checked",false);//是否选中
                    }
                    Map<String,String>  spec= (Map)JSON.parseObject(sku.getSpec()) ;//当前的Sku
                    spec.put(key,value);
                    String specJson = JSON.toJSONString(spec , SerializerFeature.MapSortField);
                    map.put("url",urlMap.get(specJson));
                    mapList.add(map);
                }
                specMap.put(key,mapList);//用新的集合替换原有的集合
            }

            dataModel.put("specMap" ,specMap);

            context.setVariables(dataModel);

            //(2)准备文件
            File dir =new File(pagePath);
            if( !dir.exists()){
                dir.mkdirs();
            }
            File dest= new File(dir, sku.getId()+".html" );

            //(3)生成页面
            try {
                PrintWriter writer=new PrintWriter( dest,"UTF-8");
                engine.process("item",context,writer );
                System.out.println("生成页面:"+sku.getId()+".html");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
    }
}

即根据查到的spuID,和相应的模板,来动态的生成页面
下面分析报错
他说我

template: "ServletContext resource [/WEB-INF/templates/item/createPage.html]"

我很好奇,我tm就没有返回什么createPage啊,怎么会突然蹦出来这个玩意,这是我controller中的方法啊,奇了怪了
再往下看。root cause1可以看出是thymeleaf模板引擎那里出了问题,再往下就是io那里出了问题,但是奇怪的是,我想要生成的页面都已经生成了
在这里插入图片描述
报错是在生成之后报错的,这个时候我感觉确实是在完成了之后返回了某些东西,导致在哪里出错了,后来找到了一些内容:
解决方案1
发现人家说了一个问题,注解的问题,才想到,确实是这样,
通过将注解:@Controller改成@RestController,完美解决
同时有另外一个问题:
有时候只可以用Controller
@RestController和@Controller的区别

@RestController注解相当于@ResponseBody + @Controller合在一起的作用。
如果使用@RestController注解,则Controller类中的方法无法返回jsp页面,配置的视图解析器InternalResourceViewResolver则不起作用,返回的内容就是Return 里的内容(String/JSON)。

@Controller标识一个Spring类是Spring MVC controller处理器
在@controller注解中,返回的是字符串,或者是字符串匹配的模板名称,通过视图解析器InternalResourceViewResolver直接渲染视图,与html/jsp页面配合使用的

回去复习springmvc了,复习好了再回来继续补充~~~~~

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐