zoukankan      html  css  js  c++  java
  • SpringBoot中Service实现类添加@Service却任然无法注入的问题

           最近一直在研究Spring Boot。从GitHub上下载了一个my-Blog源码,一边看,一边自己尝试去实现,结果掉在坑了,研究了近一周才爬出来,特地来这博客园记录下来,一是避免自己在放这样的错误,二是希望看到的朋友能有所帮助,毕竟我在网上查了很多资料,答案基本上千篇一律,并不能解决我的问题。

           先说问题:我在Controller层中引用Service层的实现类,报错,错误代码如下:

    2020-06-15 22:49:45.094 ERROR 1552 --- [nio-8081-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.example.mydemo.service.AdminUserService.login] with root cause
    
    org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.example.mydemo.service.AdminUserService.login
        at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235) ~[mybatis-3.5.4.jar:3.5.4]
        at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:53) ~[mybatis-3.5.4.jar:3.5.4]
        at org.apache.ibatis.binding.MapperProxy.lambda$cachedInvoker$0(MapperProxy.java:107) ~[mybatis-3.5.4.jar:3.5.4]
        at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[na:1.8.0_151]
        at org.apache.ibatis.binding.MapperProxy.cachedInvoker(MapperProxy.java:94) ~[mybatis-3.5.4.jar:3.5.4]
        at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:85) ~[mybatis-3.5.4.jar:3.5.4]
        at com.sun.proxy.$Proxy66.login(Unknown Source) ~[na:na]
        at com.example.mydemo.controller.admin.AdminController.login(AdminController.java:45) ~[classes/:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_151]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_151]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_151]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:215) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:142) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:998) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:901) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:875) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) ~[tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:770) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_151]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_151]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.12.jar:9.0.12]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_151]

    总的来说就是绑定语句无效,并未找到  com.example.mydemo.service.AdminUserService.login此方法。我从网上百度一下,看到大多数都是再讲Mapper.xml设置错误导致,需要排查:

    1. 检查xml文件所在package名称是否和Mapper interface所在的包名一一对应;
    2. 检查xml的namespace是否和xml文件的package名称一一对应;
    3. 检查方法名称是否对应;

    但我看了很多遍,我的程序都没有这些问题,并且我在Test中测试Mapper时可以用的。

    @SpringBootTest
    class MydemoApplicationTests {
        @Autowired
        AdminUserMapper adminUserMapper;
        @Resource
        TestService testService;
       @Test
       void TestInsert(){
           AdminUser adminUser =new AdminUser();
           adminUser.setAdminUserId(5);
           adminUser.setLocked(Byte.parseByte("1"));
           adminUser.setLoginPassword("123");
           adminUser.setLoginUserName("zzc");
           adminUser.setNickName("BigBang");
           adminUserMapper.insert(adminUser);
       }
       @Test
        void get(){
           AdminUser get= adminUserMapper.login("zzc","123");
           System.out.println(get);
        }
    
        @Test
        void TestMyService(){
           testService.Test();
        }
    }
    2020-06-15 22:59:08.234  INFO 10652 --- [           main] c.example.mydemo.MydemoApplicationTests  : Starting MydemoApplicationTests on LAPTOP-MFBL0MLV with PID 10652 (started by zc in D:Lab_JavaDemo)
    2020-06-15 22:59:08.236  INFO 10652 --- [           main] c.example.mydemo.MydemoApplicationTests  : No active profile set, falling back to default profiles: default
    2020-06-15 22:59:10.117  INFO 10652 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2020-06-15 22:59:10.814  INFO 10652 --- [           main] c.example.mydemo.MydemoApplicationTests  : Started MydemoApplicationTests in 2.776 seconds (JVM running for 4.072)
    2020-06-15 22:59:11.102  INFO 10652 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
    2020-06-15 22:59:11.287  INFO 10652 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
    AdminUser{adminUserId=1, loginUserName='zzc', loginPassword='123', nickName='BigBang', locked=0}
    2020-06-15 22:59:11.356  INFO 10652 --- [       Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
    2020-06-15 22:59:11.357  INFO 10652 --- [       Thread-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
    2020-06-15 22:59:11.359  INFO 10652 --- [       Thread-2] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
    
    Process finished with exit code 0

          可以看到get()方法是可以使用adminUserMapper的,也就是说Mapper的注入是没有问题的。此外还写了一个TestService,里面不涉及任何Mapper相关的东西,还是报这个错误。也就是说我的问题原因和Mapper并没有关系,至少不是上述这三点导致的。

    问题还是出现再Service层里,我的Service层代码如下:

    package com.example.mydemo.service;
    
    import com.example.mydemo.entity.AdminUser;
    
    public interface AdminUserService {
    
        AdminUser login(String userName, String password);
    
        /**
         * 获取用户信息
         *
         * @param loginUserId
         * @return
         */
        AdminUser getUserDetailById(Integer loginUserId);
    
        /**
         * 修改当前登录用户的密码
         *
         * @param loginUserId
         * @param originalPassword
         * @param newPassword
         * @return
         */
        Boolean updatePassword(Integer loginUserId, String originalPassword, String newPassword);
    
        /**
         * 修改当前登录用户的名称信息
         *
         * @param loginUserId
         * @param loginUserName
         * @param nickName
         * @return
         */
        Boolean updateName(Integer loginUserId, String loginUserName, String nickName);
    }
    package com.example.mydemo.service.impl;
    
    import com.example.mydemo.dao.AdminUserMapper;
    import com.example.mydemo.entity.AdminUser;
    import com.example.mydemo.service.AdminUserService;
    import com.example.mydemo.util.MD5Util;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class AdminUserServiceImpl implements AdminUserService {
    
        @Resource
        private AdminUserMapper adminUserMapper;
    
        @Override
        public AdminUser login(String userName, String password) {
            String passwordMd5 = MD5Util.MD5Encode(password, "UTF-8");
            System.out.println("Md5:"+passwordMd5);
            return adminUserMapper.login(userName, passwordMd5);
        }
    
        @Override
        public AdminUser getUserDetailById(Integer loginUserId) {
            return adminUserMapper.selectByPrimaryKey(loginUserId);
        }
    
        @Override
        public Boolean updatePassword(Integer loginUserId, String originalPassword, String newPassword) {
            AdminUser adminUser = adminUserMapper.selectByPrimaryKey(loginUserId);
            //当前用户非空才可以进行更改
            if (adminUser != null) {
                String originalPasswordMd5 = MD5Util.MD5Encode(originalPassword, "UTF-8");
                String newPasswordMd5 = MD5Util.MD5Encode(newPassword, "UTF-8");
                //比较原密码是否正确
                if (originalPasswordMd5.equals(adminUser.getLoginPassword())) {
                    //设置新密码并修改
                    adminUser.setLoginPassword(newPasswordMd5);
                    if (adminUserMapper.updateByPrimaryKeySelective(adminUser) > 0) {
                        //修改成功则返回true
                        return true;
                    }
                }
            }
            return false;
        }
    
        @Override
        public Boolean updateName(Integer loginUserId, String loginUserName, String nickName) {
            AdminUser adminUser = adminUserMapper.selectByPrimaryKey(loginUserId);
            //当前用户非空才可以进行更改
            if (adminUser != null) {
                //设置新密码并修改
                adminUser.setLoginUserName(loginUserName);
                adminUser.setNickName(nickName);
                if (adminUserMapper.updateByPrimaryKeySelective(adminUser) > 0) {
                    //修改成功则返回true
                    return true;
                }
            }
            return false;
        }
    
    
    }

    controller层中的调用如下:

    package com.example.mydemo.controller.admin;
    
    import com.example.mydemo.entity.AdminUser;
    import com.example.mydemo.service.AdminUserService;
    import org.springframework.stereotype.Controller;
    import org.springframework.util.StringUtils;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpSession;
    
    @Controller
    @RequestMapping("/admin")
    
    public class AdminController {
        @Resource
        private AdminUserService adminUserService;
    
    
    
        @GetMapping({"/login"})
        public String login() {
    
            return "admin/login";
        }
    
        @PostMapping(value = "/login")
        public String login(@RequestParam("userName") String userName,
                            @RequestParam("password") String password,
                            @RequestParam("verifyCode") String verifyCode,
                            HttpSession session){
            if (StringUtils.isEmpty(verifyCode)) {
                session.setAttribute("errorMsg", "验证码不能为空");
                return "admin/login";
            }
            if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(password)) {
                session.setAttribute("errorMsg", "用户名或密码不能为空");
                return "admin/login";
            }
            String kaptchaCode = session.getAttribute("verifyCode") + "";
            if (StringUtils.isEmpty(kaptchaCode) || !verifyCode.equals(kaptchaCode)) {
                session.setAttribute("errorMsg", "验证码错误");
                return "admin/login";
            }
            AdminUser adminUser = adminUserService.login(userName, password);
            if (adminUser != null) {
                session.setAttribute("loginUser", adminUser.getNickName());
                session.setAttribute("loginUserId", adminUser.getAdminUserId());
                //session过期时间设置为7200秒 即两小时
                //session.setMaxInactiveInterval(60 * 60 * 2);
                return "redirect:/admin/index";
            } else {
                session.setAttribute("errorMsg", "登陆失败");
                return "admin/login";
            }
    
        }
    
    }
    package com.example.mydemo;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    @MapperScan("com.example.mydemo")
    
    public class MydemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MydemoApplication.class, args);
        }
    }

           在网上查资料,发现有人说如果Application类包所在的位置也很关键,SpringBoot项目的Bean装配默认规则是根据Application类所在的包位置从上往下扫描!Application类是指SpringBoot项目入口类。也就是我的Service层所在的包必须在com.example.mydemo或其子包下,否则Service层中的Bean不会被扫描到,但我的程序也满足啊。

           结果就在这里思索了一周都没有一点进展,直到一天我发现我的@MapperScan扫描的路径是"com.example.mydemo"。WTF!!!

           我又赶快上网查了一下@MapperScan注解

           作用:指定要变成实现类的接口所在的包,然后包下面的所有接口在编译之后都会生成相应的实现类
           添加位置:是在Springboot启动类上面添加。

            看到没,包下面所有的接口在编译后之后都会生成相应的实现类,也就是说除了我的AdminUserServiceImp外Spring Boot还注入了一个mapper实现类,当我在Controller中使用@AutoWired或@Resource获取时,获取到时这个Mapper实现类的实例,但实际上并没有真正继承AdminUserService接口,只有你在运行的时候服务器才会报错,找不到对应的方法。

    于是我把Mapper扫描具体到DAO路径下,即:

    package com.example.mydemo;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    @MapperScan("com.example.mydemo.dao")
    
    public class MydemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MydemoApplication.class, args);
        }
    }

    修改后果然不再报错。

           其实这个错误说起来还是挺简单,主要时自己对Spring Boot的注解,一些基本知识还是不够了解导致,看来以后还是要继续夯实基础啊。

  • 相关阅读:
    PAT B1027 打印沙漏 (20 分)
    PAT B1025 反转链表 (25 分)
    PAT B1022 D进制的A+B (20 分)
    PAT B1018 锤子剪刀布 (20 分)
    PAT B1017 A除以B (20 分)
    PAT B1015 德才论 (25 分)
    PAT B1013 数素数 (20 分)
    PAT B1010 一元多项式求导 (25 分)
    HDU 1405 The Last Practice
    HDU 1165 Eddy's research II
  • 原文地址:https://www.cnblogs.com/Jerryoned/p/13138559.html
Copyright © 2011-2022 走看看