目录

一、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接口*/@Beanpublic 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<String, Filter> filters = shiroFilterFactoryBean.getFilters();
//        // 注意这里不要用Bean的方式,否则会报错
//        filters.put("myRole", new MyRoleFilter());
//        shiroFilterFactoryBean.setFilters(filters);shiroFilterFactoryBean.setSecurityManager(securityManager);shiroFilterFactoryBean.setLoginUrl("/unauth");shiroFilterFactoryBean.setUnauthorizedUrl("/unauth");//下面这些hashMap是定义了哪些url需要哪些权限,进行了权限管理的头文件似的声明Map<String, String> hashMap = new LinkedHashMap<>();//        hashMap.put("/**", "authc");//alipayhashMap.put("/pay", "roles[user]");hashMap.put("/return", "anon");hashMap.put("/notify", "anon");//testhashMap.put("/unauth", "anon");hashMap.put("/userTest", "roles[user]");hashMap.put("/adminTest", "roles[admin]");hashMap.put("/anonTest", "anon");hashMap.put("/exception", "anon");//swagger2hashMap.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");//accounthashMap.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");//adminhashMap.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]");//fileReaderhashMap.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")*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();//设置安全管理器attributeSourceAdvisor.setSecurityManager(securityManager);return attributeSourceAdvisor;}@Bean@ConditionalOnMissingBeanpublic 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*/@Beanpublic 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进行缓存,以提高性能;*/@BeanRedisSessionDAO redisSessionDAO() {RedisSessionDAO redisSessionDAO = new RedisSessionDAO();redisSessionDAO.setRedisManager(redisManager());return redisSessionDAO;}@BeanDefaultWebSessionManager sessionManager(RedisSessionDAO redisSessionDAO) {DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionDAO(redisSessionDAO);return sessionManager;}/*** 缓存控制器,来管理如用户、角色、权限等的缓存的;* 因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能*/@BeanRedisCacheManager 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 {@Beanpublic 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<String, String> hashMap = new LinkedHashMap<>();//swagger2hashMap.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");//accounthashMap.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]");//adminOrderhashMap.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]");//carhashMap.put("/car/list", "roles[admin]");hashMap.put("/car/add", "roles[admin]");hashMap.put("/car/delete", "roles[admin]");hashMap.put("/car/free", "roles[admin]");//driverhashMap.put("/driver/list", "roles[admin]");hashMap.put("/driver/add", "roles[admin]");hashMap.put("/driver/delete", "roles[admin]");hashMap.put("/driver/free", "roles[admin]");//userOrderhashMap.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")*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();//设置安全管理器attributeSourceAdvisor.setSecurityManager(securityManager);return attributeSourceAdvisor;}@Bean@ConditionalOnMissingBeanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();defaultAAP.setProxyTargetClass(true);return defaultAAP;}// shiro-redis//====== session共享 ========/*** 配置shiro redisManager* 使用的是shiro-redis开源插件** @return*/@Beanpublic 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进行缓存,以提高性能;*/@BeanRedisSessionDAO redisSessionDAO() {RedisSessionDAO redisSessionDAO = new RedisSessionDAO();redisSessionDAO.setRedisManager(redisManager());return redisSessionDAO;}@BeanDefaultWebSessionManager sessionManager(RedisSessionDAO redisSessionDAO) {DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionDAO(redisSessionDAO);return sessionManager;}/*** 缓存控制器,来管理如用户、角色、权限等的缓存的;* 因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能*/@BeanRedisCacheManager 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的认证方法:

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 {@AutowiredUserMapper userMapper;@AutowiredAdminMapper adminMapper;//授权@Overrideprotected 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*/@Overrideprotected 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作为副键,登录时输入用户名和密码。

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

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

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


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

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

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

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

但是我在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返回详情时,即使我的数据库里有东西,返回出来也是这样的:

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

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

芜湖成功!

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

学到了学到了


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

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

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

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

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

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

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

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

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

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

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

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

我根本没分页!!!

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

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

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

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

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

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

    @Overridepublic Page<TmpAdminOrder> 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<TmpAdminOrder> briefAdminOrderPage = new Page<>();if(status!=4)  briefAdminOrderPage = new Page<TmpAdminOrder>(new PageInfo<TmpAdminOrder>(adminOrderMapper.getBriefAdminOrderListByStatus(status)));else briefAdminOrderPage = new Page<TmpAdminOrder>(new PageInfo<TmpAdminOrder>(adminOrderMapper.getBriefAdminOrderList()));List<TmpAdminOrder> 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窗口:

先clean,再compile:

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

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


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

这个真的有用!

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

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

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

它就会报错:

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

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

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

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


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

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

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

但是postman的报错是这样的:

但是我的语法没啥错呀?

于是我就开始各种改:

加个分号:

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

甚至把整句话截到一半:

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

汗毛耸立······

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

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

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

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

至此解决!


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

接口文档: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

J2EE大作业遇到的问题及解决方案:相关推荐

  1. java大作业私人管家系统_操作系统概念(Operating System Concepts)第十版期中大作业...

    更正: 第一题中,哲学家就餐问题中的哲学家的状态state[i]应属于临界区变量,是可能会产生读写冲突的,所以对其进行读写的时候均需要加一把互斥锁. 非常感谢不听不听不听的指正. ---------- ...

  2. 东华大学java_东华大学2020秋《Java程序设计》期末大作业

    东华大学继续教育学院 2020年秋季学期 远程学历教育<Java程序设计>期末大作业 一.选择题(本大题共10小题,每小题 1分, 共10分) 1.    下列哪个不是面向对象程序设计的基 ...

  3. 2020级C语言大作业 - 丛林大作战

    丛林大作战_C语言大作业 分享20级同学大一上学期用C语言(及少量C++)实现的丛林大作战游戏.由于同学们刚学了三个月的编程,实现还不够完善,工程代码.图片音乐素材可以从百度网盘下载: 链接:http ...

  4. 学委作业管理系统c语言,c语言大作业-学生信息管理系统.doc

    c语言大作业-学生信息管理系统.doc 课程设计报告书 题目:学生信息管理系统设计 学 院 电子与信息学院 专 业 电子信息类 学生姓名 学生学号 指导教师 课程编号 135160 课程学分 1学分 ...

  5. 爬虫大作业~以爬取hao123漫画为例

    一.准备过程 首先打开hao123漫画筛选区,网址是https://www.hao123.com/manhua/list/?finish=&audience=&area=&ca ...

  6. python爬虫大作业任务书_爬虫大作业

    通过 爬取2345电影网的电影信息 ,通过电影的类型和评分分别生成相应的词云 进行数据分析 一.准备过程 首先打开2345电影网的热播电影区,网址是https://dianying.2345.com/ ...

  7. 【安卓开发】简单记账app功能实现开发-期末大作业个人总结

    说在前面: 由于这一次的大作业涉及到的代码部分过于长,所以博客里不放相关代码: 工程&apk&记账app原型&素材资源链接:https://download.csdn.net/ ...

  8. HTML+CSS静态页面网页设计作业——餐饮店铺(1页) web前端设计与开发期末作品_期末大作业

    HTML5期末大作业:餐饮网站设计--餐饮店铺(1页) 文章目录 HTML5期末大作业:餐饮网站设计--餐饮店铺(1页) 一.作品展示 二.文件目录 三.代码实现 四.获取更多源码 一.作品展示 二. ...

  9. 《信息检索》课程大作业 实现一个本地搜索引擎

    <先锋检索>--开发文档 也是本人的第一篇博客 这篇博客是本人<信息检索>课程大作业的开发文档,使用了larbin(网络爬虫)+xunsearch(搜索引擎解决方案)的解决方案 ...

最新文章

  1. 通俗易懂的TCP里面的三次握手以及四次挥手
  2. 移动全平台性能测试工具PerfDog--安装及运行
  3. 使用gparted live分区工具对VMware及ESXI(vsphere)虚拟机进行根目录扩容(可视化界面操作)
  4. openstack基于mysql的问题修复
  5. python之路_Python之路
  6. Java UDP协议传输
  7. SAP Spartacus central configuration - B2cStorefrontModule
  8. CentOS升级Python2.7及安装pip
  9. 使用SparkJava和Graal的本机微服务
  10. 3-6:类与对象下篇——构造函数中的初始化列表、匿名对象和explicit关键字
  11. HDU 1151 Air Raid
  12. 远程使用plsql登陆数据库时,界面提示 ORA-12170 TNS 连接超时
  13. Julia: array =tuple, 与 ...
  14. Matlab图像处理--低通滤波器的Matlab实现及透视图
  15. TEM014 - 新版阿里云网站界面高保真原型模板-AxureUX
  16. Uiautomator 2.0之UiObject2类学习小记
  17. ASCII、GB2312、GBK、GB18030、Unicode、UTF-8、BIG5 编码分析
  18. sl4a+android截屏,使用SL4A Python在android桌面上显示数据(示例)
  19. React+Dva使用d3绘图
  20. KY261 Jugs

热门文章

  1. 云计算 码率适配限速_一种基于云计算的应用于用户终端的测速方法
  2. jQuery伪类选择器
  3. c语言case什么,switch
  4. Call to undefined function imagecreatefromjpeg() 解决方案
  5. 计算机网络知识储备(一)
  6. Ubuntu20.04+Linux5.8.8 添加系统调用实现进程隐藏
  7. c语言主函数调用函数
  8. PowerBI visuals共计246组2020年1月31日扒取(Power BI 视觉对象)
  9. 面试题之你是如何优化你的网站的?
  10. 朝九晚五IT人生活不容易啊