J2EE大作业遇到的问题及解决方案:

目录

一、Shiro框架的平稳对接

二、mapper无法正确映射,Dao层找不到数据

三、pageHelper失效,分页分了个寂寞

四、偶尔找不到符号/编译器无法解析

 五、如何对类型为Integer的字段进行模糊搜索

六、SQL语句改了,但是报错中的SQL语句一直不变


​​​​​​​

一、Shiro框架的平稳对接

完事开头难。一个非纯信息展示平台,也就是有着增删改查功能的平台,首先遇到的问题就是会话维持和权限管理。毕竟我不能创建别人的订单,别人也不能代替我进行收货。

我们的项目决定采用shiro进行会话维持和权限管理,那我们首先来fork一个使用了shiro工具的网站后端的源码,来看它在哪里用到了shiro以及怎么用的:

以下代码部分是有关shiro的配置、权限声明以及shiro-redis缓冲区的配置。阅读代码后加上了所有的注释,并对其进行测试运行。

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import undestiny.stell.shiro.MyRealm;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

@Slf4j
@Component
public class ShiroConfig {


    /*DefaultWebSecurityManager类主要定义了设置subjectDao,获取会话模式,设置会话模式,设置会 
     *话管理器,是否是http会话模式等操作,它继承了DefaultSecurityManager类,实现了 
     *WebSecurityManager接口
     */
    @Bean
    public DefaultWebSecurityManager securityManager(MyRealm realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        securityManager.setRealm(realm);
        log.info("securityManager -----------> 初始化了");
        return securityManager;
    }

    //一个shiro过滤器初始化的工厂方法
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();


//        //自定义过滤器
//        Map filters = shiroFilterFactoryBean.getFilters();
//        // 注意这里不要用Bean的方式,否则会报错
//        filters.put("myRole", new MyRoleFilter());
//        shiroFilterFactoryBean.setFilters(filters);


        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/unauth");
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");


        //下面这些hashMap是定义了哪些url需要哪些权限,进行了权限管理的头文件似的声明
        Map hashMap = new LinkedHashMap<>();

//        hashMap.put("/**", "authc");
        //alipay
        hashMap.put("/pay", "roles[user]");
        hashMap.put("/return", "anon");
        hashMap.put("/notify", "anon");

        //test
        hashMap.put("/unauth", "anon");
        hashMap.put("/userTest", "roles[user]");
        hashMap.put("/adminTest", "roles[admin]");
        hashMap.put("/anonTest", "anon");
        hashMap.put("/exception", "anon");



        //swagger2
        hashMap.put("/swagger-ui.html", "anon");
        hashMap.put("/swagger/**", "anon");
        hashMap.put("/swagger-resources/**", "anon");
        hashMap.put("/v2/**", "anon");
        hashMap.put("/webjars/**", "anon");
        hashMap.put("/configuration/**", "anon");

        //account
        hashMap.put("/password", "anon");
        hashMap.put("/verifyCode/password", "anon");
//        hashMap.put("/auth", "roles[user]");
        hashMap.put("/signIn", "anon");
        hashMap.put("/signOut", "anon");
        hashMap.put("/signUp", "anon");
        hashMap.put("/signUp/**", "anon");

        //admin
        hashMap.put("/admin", "roles[admin]");
        hashMap.put("/admin/userLogin/today", "roles[admin]");
        hashMap.put("/admin/member", "roles[admin]");
        hashMap.put("/admin/buyHistoryStatics", "roles[admin]");
        hashMap.put("/admin/buyHistoryStatics/**", "roles[admin]");
        hashMap.put("/admin/ buyHistory", "roles[admin]");

        //company
//        hashMap.put("/company", "myRole[company]");
//        hashMap.put("/company/**", "myRole[company]");

        //fileReader
        hashMap.put("/file/company/logo/**", "anon");
        hashMap.put("/file/company/content/**", "anon");

        //homepage
//        hashMap.put("/collection", "roles[user]");
//        hashMap.put("/collection/**", "roles[user]");
        hashMap.put("/homepage/**", "anon");
        hashMap.put("/search/**", "anon");
        hashMap.put("/visit/**", "anon");

//        //member
//        hashMap.put("/member", "roles[user]");
//        hashMap.put("/member/**", "roles[user]");


        hashMap.put("/**", "anon");



        shiroFilterFactoryBean.setFilterChainDefinitionMap(hashMap);

        return shiroFilterFactoryBean;
    }

    /**
     * 开启aop注解支持
     * 即在controller中使用 @RequiresPermissions("user/userList")
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        //设置安全管理器
        attributeSourceAdvisor.setSecurityManager(securityManager);
        return attributeSourceAdvisor;
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

//    /**
//     * 处理未授权的异常,返回自定义的错误页面(403)
//     * @return
//     */
//    @Bean
//    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
//        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
//        Properties properties = new Properties();
//        /*未授权处理页*/
//        properties.setProperty("UnauthorizedException", "classpath:403.html");
//        resolver.setExceptionMappings(properties);
//        return resolver;
//    }





    // shiro-redis
    //====== session共享 ========
    /**
     * 配置shiro redisManager
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("127.0.0.1:6379");
        redisManager.setDatabase(0);
        return redisManager;
    }

    /**
     * DAO大家都用过,数据访问对象,用于会话的CRUD,比如我们想把Session保存到数据库,那么可以实现自己的SessionDAO,
     * 通过如JDBC写到数据库;比如想把Session放到Memcached中,可以实现自己的Memcached SessionDAO;
     * 另外SessionDAO中可以使用Cache进行缓存,以提高性能;
     */
    @Bean
    RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    @Bean
    DefaultWebSessionManager sessionManager(RedisSessionDAO redisSessionDAO) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO);
        return sessionManager;
    }

    /**
     * 缓存控制器,来管理如用户、角色、权限等的缓存的;
     * 因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能
     */
    @Bean
    RedisCacheManager redisCacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        //redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识)
        redisCacheManager.setPrincipalIdFieldName("id");
        //用户权限信息缓存时间
        redisCacheManager.setExpire(200000);
        return redisCacheManager;
    }

}

在此基础上进行修改,使其适配我们的项目:

package com.phoenix.logistics.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import com.phoenix.logistics.shiro.MyRealm;

import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
@Component
public class ShiroConfig {

    @Bean
    public DefaultWebSecurityManager securityManager(MyRealm realm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        securityManager.setRealm(realm);
        log.info("securityManager -----------> 初始化了");
        return securityManager;
    }

    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/unauth");
        shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");
        

        Map hashMap = new LinkedHashMap<>();

        //swagger2
        hashMap.put("/swagger-ui.html", "anon");
        hashMap.put("/swagger/**", "anon");
        hashMap.put("/swagger-resources/**", "anon");
        hashMap.put("/v2/**", "anon");
        hashMap.put("/webjars/**", "anon");
        hashMap.put("/configuration/**", "anon");

        //account
        hashMap.put("/account/checkPassword", "anon");
        hashMap.put("/account/changPassword", "anon");
        hashMap.put("/account/changMessage", "anon");
        hashMap.put("/account/checkUsername", "anon");
        hashMap.put("/account/signIn", "anon");
        hashMap.put("/account/signOut", "anon");
        hashMap.put("/account/signUp", "anon");
        hashMap.put("/account/user/all", "roles[user]");

        //adminOrder
        hashMap.put("/admin_order/deal", "roles[admin]");
        hashMap.put("/admin_order/detail", "roles[admin]");
        hashMap.put("/admin_order/message", "roles[admin]");
        hashMap.put("/admin_order/search", "roles[admin]");
        hashMap.put("/admin_order/list", "roles[admin]");
        
        //car
        hashMap.put("/car/list", "roles[admin]");
        hashMap.put("/car/add", "roles[admin]");
        hashMap.put("/car/delete", "roles[admin]");
        hashMap.put("/car/free", "roles[admin]");

        //driver
        hashMap.put("/driver/list", "roles[admin]");
        hashMap.put("/driver/add", "roles[admin]");
        hashMap.put("/driver/delete", "roles[admin]");
        hashMap.put("/driver/free", "roles[admin]");

        //userOrder
        hashMap.put("/user_order/submit", "roles[user]");
        hashMap.put("/user_order/detail", "roles[user]");
        hashMap.put("/user_order/message", "roles[user]");
        hashMap.put("/user_order/search", "roles[user]");
        hashMap.put("/user_order/list", "roles[user]");
        hashMap.put("/user_order/receive", "roles[user]");


        shiroFilterFactoryBean.setFilterChainDefinitionMap(hashMap);

        return shiroFilterFactoryBean;
    }

    /**
     * 开启aop注解支持
     * 即在controller中使用 @RequiresPermissions("user/userList")
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        //设置安全管理器
        attributeSourceAdvisor.setSecurityManager(securityManager);
        return attributeSourceAdvisor;
    }

    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }
    
    


    // shiro-redis
    //====== session共享 ========
    /**
     * 配置shiro redisManager
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("127.0.0.1:6379");
        redisManager.setDatabase(0);
        return redisManager;
    }

    /**
     * DAO大家都用过,数据访问对象,用于会话的CRUD,比如我们想把Session保存到数据库,那么可以实现自己的SessionDAO,
     * 通过如JDBC写到数据库;比如想把Session放到Memcached中,可以实现自己的Memcached SessionDAO;
     * 另外SessionDAO中可以使用Cache进行缓存,以提高性能;
     */
    @Bean
    RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    @Bean
    DefaultWebSessionManager sessionManager(RedisSessionDAO redisSessionDAO) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO);
        return sessionManager;
    }

    /**
     * 缓存控制器,来管理如用户、角色、权限等的缓存的;
     * 因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能
     */
    @Bean
    RedisCacheManager redisCacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        //redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识)
        redisCacheManager.setPrincipalIdFieldName("id");
        //用户权限信息缓存时间
        redisCacheManager.setExpire(200000);
        return redisCacheManager;
    }

}

配置初步完成,剩下的就是在适当的地方进行使用了。

首先我们看如何登录:

@RestController
@Api("登录Controller")
@Validated
@RequestMapping("/account")
public class AccountController {

    @PostMapping("/signIn")
    @ApiOperation("登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "用户名", required = true, paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "password", value = "密码(长度6-20)", required = true, paramType = "query", dataType = "String")
    })
    public Result doLogin(@RequestParam("username")@NotNull String username, @RequestParam("password")@NotNull @Size(min = 6,max = 20)String password) {

        if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            return Result.fail("用户名或密码不能为空!");
        }
        AuthenticationToken token = new UsernamePasswordToken(username, PasswordUtil.convert(password));

        try {

            //尝试登陆,将会调用realm的认证方法
            SecurityUtils.getSubject().login(token);

        }catch (AuthenticationException e) {
            if (e instanceof UnknownAccountException) {
                return Result.fail("用户不存在");
            } else if (e instanceof LockedAccountException) {
                return Result.fail("用户被禁用");
            } else if (e instanceof IncorrectCredentialsException) {
                return Result.fail("密码错误");
            } else {
                return Result.fail("用户认证失败");
            }
        }

        UserDTO principal = (UserDTO) SecurityUtils.getSubject().getPrincipal();
        if(principal.getType()==1) return Result.success("登录成功",principal);
        return Result.success("登录成功", new GetUserResponse(accountService.getUser(username),principal.getType()));
    }

可以看到,登录在controller里是通过shiro提供的SecurityUtils.getSubject.login(token)方法来实现的,这里会调用realm的认证方法:

J2EE大作业遇到的问题及解决方案:_第1张图片

package com.phoenix.logistics.shiro;

import com.phoenix.logistics.dto.UserDTO;
import com.phoenix.logistics.entity.Admin;
import com.phoenix.logistics.entity.User;
import com.phoenix.logistics.mapper.AdminMapper;
import com.phoenix.logistics.mapper.UserMapper;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class MyRealm extends AuthorizingRealm {

    @Autowired
    UserMapper userMapper;

    @Autowired
    AdminMapper adminMapper;


    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        Object principal = principals.getPrimaryPrincipal();
        UserDTO userDTO = (UserDTO) principal;

        String username = userDTO.getUsername();
        int type = userDTO.getType();

        //注入角色与权限
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //管理员
        if(type == 1)
            info.addRole("admin");

        //普通用户
        if(type == 0)
            info.addRole("user");
        
        return info;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        //数据库匹配,认证
        String username = token.getUsername();
        String password = new String(token.getPassword());

        //管理员
        Admin admin = adminMapper.getAdminByUsername(username);
        if(admin != null && (admin.getPassword()+"").equals(password)){
            UserDTO userDTO = new UserDTO(admin);

            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userDTO, token.getCredentials(), getName());
            return info;
        }

        //普通用户
        User user = userMapper.getUserByUsername(username);
        if(user != null && (user.getPassword()+"").equals(password)){
            UserDTO userDTO = new UserDTO(user);

            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userDTO, token.getCredentials(), getName());
            return info;
        }

        //认证失败
        throw new AuthenticationException();
    }
}

由于我们这个项目是物流管理项目,管理员负责增删改查车辆和司机,用户主要可以提交和查看自己的订单,而且用户和管理员的功能并没有很多重合的地方,所以我们以不同的身份登录时会在info中增加不同的role,而且管理员这边不会增加用户的role,所以管理员是没有用户的功能权限的。

还有一点是,我们使用的shiro工具,它自己所带的UsernamePasswordToken是使用名为username的字符串类型的字段进行用户验证的(而且个人觉得用Long类型的id作为用户名也不是很妥,用户体验也不好),所以我们在User类中将username作为副键,登录时输入用户名和密码。

并且我们在异常这里控制好返回的信息,一旦出现账号相关的错误,就返回相应的异常信息。

J2EE大作业遇到的问题及解决方案:_第2张图片

J2EE大作业遇到的问题及解决方案:_第3张图片

J2EE大作业遇到的问题及解决方案:_第4张图片

 这样我们就可以在其他接口中维持此用户的登录状态了!只有正确登录才能执行相应的方法:有RequireRole为user的方法要以用户身份登录用户账户,有RequireRole为admin的方法要以管理员身份登录管理员账户。不登录就调用方法,就会出现以下报错:

J2EE大作业遇到的问题及解决方案:_第5张图片

 至此,shiro工具就配置好了,我们会话的维持功能就做好啦!


二、mapper无法正确映射,Dao层找不到数据

很多东西,用别人的架子是察觉不到的,只有自己做对接才能发现很多脑残的细节。

根据自己的经验,我一开始做的数据库设计,是这样的:

J2EE大作业遇到的问题及解决方案:_第6张图片

可以看到,我喜欢把数据库里的字段单词之间用下划线隔开。(我们姑且称为下划线命名法)

但是我在entity包中采用的字段命名是这样的:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ApiModel("ControllerOrder 管理员订单")
public class AdminOrder implements Serializable {

    @Id
    @ApiModelProperty("id")
    private Long id;

    @ApiModelProperty("用户订单id")
    private Long userOrderId;

    @ApiModelProperty("货物id")
    private Long goodsId;

    @ApiModelProperty("车辆id")
    private Long carId;

    @ApiModelProperty("司机id")
    private Long driverId;

    @ApiModelProperty("管理员用户名")
    private String adminUsername;

    @ApiModelProperty("状态")
    private Integer status;

    @ApiModelProperty("状态更新时间")
    private String statusUpdateTime;

    @ApiModelProperty("预计运输时间(以小时为单位)")
    private Integer transportTime;

    @ApiModelProperty("发货时间")
    private String sendTime;

    @ApiModelProperty("送达时间")
    private String arriveTime;

    @ApiModelProperty("是否已读")
    private Integer isRead;

    public AdminOrder(Long userOrderId, Long goodsId, Integer status, String statusUpdateTime,Integer transportTime,Integer isRead) {
        this.userOrderId = userOrderId;
        this.goodsId = goodsId;
        this.status = status;
        this.statusUpdateTime = statusUpdateTime;
        this.transportTime = transportTime;
        this.isRead = isRead;
    }
}

显然用的是标准的驼峰命名法。这样我在通过id返回详情时,即使我的数据库里有东西,返回出来也是这样的:

J2EE大作业遇到的问题及解决方案:_第7张图片

 发现问题是因为只有status有信息,而刚刚好status是下划线命名法和驼峰命名法一样的那个。

解决方法当然是把数据库里的字段都改成标准的驼峰命名法,之后再测试这个方法:

J2EE大作业遇到的问题及解决方案:_第8张图片

芜湖成功!

因为我在发现这个问题之前一直以为是一个mapper的bean注入到不同的service里返回不同了,我想想不太可能,问了学长,学长让我拉出来单写接口,只用mapper,合在一个service里,结果相同:果然不是mapper的问题,才往mapper本身和数据库方面想。后来改完再问学长,学长说其实要自己做数据库和mapper的映射才行,否则MyMapper自己是找不到名称不同的数据库字段的。

学到了学到了


三、pageHelper失效,分页分了个寂寞

这个问题分两个阶段解决的,分别解决的也是两个小的问题:

1.分页之后要的不是所要求的那页,而是返回了所有的信息

2.分页之后,pages和total显示的都是0

第一个问题在于:我们在设计时想要分不同的种类展示,像淘宝的订单展示一样:

J2EE大作业遇到的问题及解决方案:_第9张图片

 而这些订单列表的展示都是做在一个service里的(为了良好的代码复用性和封装性),根据前端传来的参数进行筛选,这样的话,要求哪些订单,返回的分页的各个参数也就都要不同。

最最开始的时候,我们将mapper封装的很好,只有一个返回所有订单的接口给service用,然后在service里再进行信息的分类和补全等等,但是这样的话必然没法做到通过pageHelper来分页了,只能返回一个个列表,而不是一个一个页,所以我们又把mapper进行一定程度的拆分,拆成如下:

    @Select("SELECT id,userOrderId,status,statusUpdateTime,goodsId FROM adminOrder")
    List getBriefAdminOrderList();

    @Select("SELECT id,userOrderId,status,statusUpdateTime,goodsId FROM adminOrder WHERE status=#{status}")
    List getBriefAdminOrderListByStatus(@Param("status")Integer status);

 变成全部和分状态获取,这样可以在service里获取分好页的Page,再对该页的每一项进行信息的补全就行了。(相当于把分类放到mapper里做了)

就当我觉得自己方案完美,必没问题时,我发现我的orderBy字段好像没用了,即使我传的是desc,给我的也是按asc排的序,而且我传的是“statusUpdateTime desc",它给我的是"id asc":

J2EE大作业遇到的问题及解决方案:_第10张图片

 我开始觉得是排序不对,于是我在该网站上搜了好多有关startPage和orderBy的问题······

直到我发现,即使我的pageSize==1,它也给了我数据库里所有的东西······

我根本没分页!!!

我可以回退到学pageHelper怎么用了(唉······

J2EE大作业遇到的问题及解决方案:_第11张图片

原来是要让MyBatis查询语句紧随其后,那我就知道怎么改了:

J2EE大作业遇到的问题及解决方案:_第12张图片

然后第一个小问题就解决了!

第二个小问题,发现于前端找我要pages时,我发现我返回的pages,和total一直是0。

找了好久,发现是数据处理的问题,我不应该创建一个新的列表,返回的时候包装这个列表,那一开始startPage还有什么意义?

我们应该直接在页内改动,或者获取它在mybatis的select语句得到的pages和total,再赋给我们要返回的新页:

    @Override
    public Page getBriefAdminOrderListByStatus(int pageNum, int pageSize,int status){
        if(status==0)PageHelper.startPage(pageNum, pageSize,"statusUpdateTime asc");
        else PageHelper.startPage(pageNum, pageSize,"statusUpdateTime desc");
        if(status==2||status==3) updateTransportingAdminOrderStatus();
        Page briefAdminOrderPage = new Page<>();
        if(status!=4)  briefAdminOrderPage = new Page(new PageInfo(adminOrderMapper.getBriefAdminOrderListByStatus(status)));
        else briefAdminOrderPage = new Page(new PageInfo(adminOrderMapper.getBriefAdminOrderList()));
        List briefAdminOrderArrayList = briefAdminOrderPage.getItems();
        for(TmpAdminOrder adminOrder:briefAdminOrderArrayList){
            UserOrder userOrder = userOrderMapper.getUserOrderById(adminOrder.getUserOrderId());
            Goods goods = goodsMapper.getGoodsById(adminOrder.getGoodsId());
            adminOrder.setGoodsName(goods.getName());
            adminOrder.setGoodsType(goods.getType().getDescription());
            adminOrder.setSenderUsername(userOrder.getSenderUsername());
            adminOrder.setReceiverUsername(userOrder.getReceiverUsername());
        }
        briefAdminOrderPage.setItems(briefAdminOrderArrayList);
        return briefAdminOrderPage;
    }

如上解决!


四、偶尔找不到符号/编译器无法解析

这个解决方案有时候确实是万能的:

如果明明你的代码写的不能再对了,报了个找不到符号,但是你的import写的很明白啊?!

这时候你只需要:

打开maven窗口:

J2EE大作业遇到的问题及解决方案:_第13张图片

 先clean,再compile:

J2EE大作业遇到的问题及解决方案:_第14张图片

毕竟有的时候只是因为的你的包没下载完······

如果还不行,可以考虑直奔./m2文件下删所下的文件,再重新compile


 五、如何对类型为Integer的字段进行模糊搜索

这个真的有用!

我们的订单列表设置的搜索框用的是针对id的模糊搜索,但是id字段因为要符合数据库中的自动递增,所以我们设置成为了Long类型。

但是这样的话,如果我们的SQL语句这样写:

    @Select("SELECT id,userOrderId,status,statusUpdateTime,goodsId FROM adminOrder WHERE id LIKE %#{id}")
    List searchAdminOrder(@Param("id")Integer id);

它就会报错:

J2EE大作业遇到的问题及解决方案:_第15张图片

进而我们发现数字类型没法简单的通配符······

又是寻觅良久,找到解决方案: 

    @Select("SELECT id,userOrderId,status,statusUpdateTime,goodsId FROM adminOrder WHERE id LIKE CONCAT('%',#{id,jdbcType=VARCHAR},'%')")
    List searchAdminOrder(@Param("id")Integer id);

 只要这么写,它就能跑出来了!


六、SQL语句改了,但是报错中的SQL语句一直不变

这个是我第一个写到脊背发凉,想念着佛经调的bug

我的DELETE方法一直天衣无缝:

J2EE大作业遇到的问题及解决方案:_第16张图片

但是postman的报错是这样的:

J2EE大作业遇到的问题及解决方案:_第17张图片

 但是我的语法没啥错呀?

于是我就开始各种改:

加个分号:

J2EE大作业遇到的问题及解决方案:_第18张图片

J2EE大作业遇到的问题及解决方案:_第19张图片

 改个语句顺序(虽然不知道对不对):

J2EE大作业遇到的问题及解决方案:_第20张图片

J2EE大作业遇到的问题及解决方案:_第21张图片

 甚至把整句话截到一半:

J2EE大作业遇到的问题及解决方案:_第22张图片

J2EE大作业遇到的问题及解决方案:_第23张图片

 我的报错里面的SQL语句变都没有变!!!

汗毛耸立······

直到我注意到了报错中的这一句:

J2EE大作业遇到的问题及解决方案:_第24张图片

我才发现:原来我的select语句没有打星号,导致java自己把SELECT和DELETE方法做成了内联方法?!

J2EE大作业遇到的问题及解决方案:_第25张图片

 所以以后不要抓着一个语句不放,也看看其他可能的错误!+好好看报错信息!!

这样将SELECT方法的语句改正确之后:

J2EE大作业遇到的问题及解决方案:_第26张图片

J2EE大作业遇到的问题及解决方案:_第27张图片

 至此解决!


 以上就是我在写后端时碰到的主要几个大问题和解决方案,以下是项目的相关资源:

接口文档:Swagger UIhttp://1.15.30.214:8081/swagger-ui.html#/

项目仓库(12.29开源):

logistics: J2EE大作业 网页版物流平台 (gitee.com)https://gitee.com/phoenix1975/logistics个人gitee仓库:

仓库 - 凤雏 (phoenix1975) - Gitee.comhttps://gitee.com/phoenix1975/projects

你可能感兴趣的:(java,开发语言,spring,boot,web,app,后端)