实训项目复盘

1. SpringBoot框架搭建

(待编辑)

2. Mybatis逆向工程生成实体类、mapper及其映射文件

  1. pom.xml引入Mybatis Generator Core依赖

    <dependency>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-core</artifactId>
        <version>1.3.7</version>
    </dependency>
    
  2. resources路径下创建下generatorConfig.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfiguration
            PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
            "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    <generatorConfiguration>
        <context id="DB2Tables" targetRuntime="MyBatis3">
    <!--         生成mysql带有分页的sql的插件  这个可以自己写,-->
    <!--        <plugin type="generator.MysqlPaginationPlugin" />-->
            <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
            <plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
            <!--取消生成注释-->
            <commentGenerator>
                <property name="suppressDate" value="true"/>
                <property name="suppressAllComments" value="true" />
            </commentGenerator>
            <!--连接数据库-->
            <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/demo"
                            userId="root"
                            password="123">
            </jdbcConnection>
            <!--生成entity类存放位置-->
            <javaModelGenerator targetPackage="com.example.demo.entity" targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true"/>
                <property name="trimStrings" value="true"/>
            </javaModelGenerator>
            <!--生成映射文件存放位置-->
            <sqlMapGenerator targetPackage="com.example.demo.mapper" targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true"/>
            </sqlMapGenerator>
            <!--生成Dao类存放位置-->
            <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.demo.dao"
                                 targetProject=".\src\main\java">
                <property name="enableSubPackages" value="true"/>
            </javaClientGenerator>
            <!--需要逆向分析的表 表名+类名-->
            <table tableName="dishes" domainObjectName="Dishes"></table>
            <table tableName="dishorder" domainObjectName="DishOrder"></table>
        </context>
    </generatorConfiguration>
    
  3. 编写可执行方法

    void testMBG() throws Exception {
        List<String> warnings = new ArrayList<String>();
        boolean overwrite = true;
        File configFile = new File("generatorConfig.xml");
        ConfigurationParser cp = new ConfigurationParser(warnings);
        Configuration config = cp.parseConfiguration(configFile);
        DefaultShellCallback callback = new DefaultShellCallback(overwrite);
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        myBatisGenerator.generate(null);
    }
    

找不到文件问题:new File(绝对路径)

3. springboot集成shiro、JWT框架实现身份认证、角色授权

(待编辑)

4.springboot集成websocket

参考链接

  1. 引入websocket相关依赖

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    
  2. 创建WebSocketConfig配置文件

    @Configuration
    public class WebSocketConfig {
       /**
        * 注入一个ServerEndpointExporter,该Bean会自动注册使用@ServerEndpoint注解申明的websocket endpoint
        */
       @Bean
       public ServerEndpointExporter serverEndpointExporter() {
           return new ServerEndpointExporter();
       }
    
    }
    
  3. 创建WebSocketService文件,相当于一个工具类。既有四个和WeSocket连接状态相关的方法(onOpen、onClose、onMessage、onError),又有自定义的用于发送实时消息的一些静态方法

    @ServerEndpoint(value = "/websocket/{userName}/{roleId}")
    @Component
    public class WebSocketService {
    
      private static final Logger log = LoggerFactory.getLogger(WebSocketService.class);
    
      //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
      private static int onlineCount = 0;
    
      //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
      private static ConcurrentHashMap<String, WebSocketClient> webSocketMap = new ConcurrentHashMap<>();
    
      /**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
      private Session session;
      /**接收userName*/
      private String userName="";
      /**接收roleId*/
      private Integer roleId=-1;
      /**
       * 连接建立成功调用的方法*/
      @OnOpen
      public void onOpen(Session session, @PathParam("userName") String userName,@PathParam("roleId")Integer roleId) {
          if(!webSocketMap.containsKey(userName))
          {
              addOnlineCount(); // 在线数 +1
          }
          this.session = session;
          this.userName= userName;
          this.roleId = roleId;
          WebSocketClient client = new WebSocketClient();
          client.setSession(session);
          client.setUri(session.getRequestURI().toString());
          client.setRoleId(roleId);
          webSocketMap.put(userName, client);
    
          log.info("----------------------------------------------------------------------------");
          log.info("用户连接:"+userName+"角色id"+roleId+",当前在线人数为:" + getOnlineCount());
          sendAllMessage(userName,userName+"已登录");
      }
    
      /**
       * 连接关闭调用的方法
       */
      @OnClose
      public void onClose() {
          if(webSocketMap.containsKey(userName)){
              webSocketMap.remove(userName);
              if(webSocketMap.size()>0)
              {
                  //从set中删除
                  subOnlineCount();
              }
          }
          log.info("----------------------------------------------------------------------------");
          log.info(userName+"用户退出,当前在线人数为:" + getOnlineCount());
      }
    
      /**
       * 收到客户端消息后调用的方法
       *
       * @param message 客户端发送过来的消息*/
      @OnMessage
      public void onMessage(String message, Session session) {
          log.info("收到用户消息:"+userName+",报文:"+message);
          //可以群发消息
          //消息保存到数据库、redis
    //        if(StringUtils.isNotBlank(message)){
    //
    //        }
      }
    
      /**
       *
       * @param session
       * @param error
       */
      @OnError
      public void onError(Session session, Throwable error) {
          log.error("用户错误:"+this.userName+",原因:"+error.getMessage());
          error.printStackTrace();
      }
    
      /**
       * 连接服务器成功后主动推送
       */
      public void sendMessage(String message) throws IOException {
          synchronized (session){
              this.session.getBasicRemote().sendText(message);
          }
      }
    
      /**
       * 向指定客户端发送消息
       * @param userName
       * @param message
       */
      public static void sendMessage(String userName,String message){
          try {
              WebSocketClient webSocketClient = webSocketMap.get(userName);
              if(webSocketClient!=null){
                  webSocketClient.getSession().getBasicRemote().sendText(message);
              }
          } catch (IOException e) {
              e.printStackTrace();
              throw new RuntimeException(e.getMessage());
          }
      }
    
      /**
       * 给所有人员发公告
       * @param message
       */
      public static void sendAllMessage(String userName,String message) {
          try {
              for (Map.Entry entry:webSocketMap.entrySet()) {
    //                if (userName.equals(entry.getKey())) continue;
                  WebSocketClient client = (WebSocketClient)entry.getValue();
                  client.getSession().getBasicRemote().sendText(message);
              }
          } catch (Exception e) {
              log.error("服务端发送消息给客户端失败", e);
          }
      }
    
      /**
       * 给厨师发送订单消息
       * @return
       */
      public static void sendMessageToCook(String message){
          try{
              for (WebSocketClient client: webSocketMap.values()){
    
                  if (client.getRoleId() != 2) continue;
                  System.out.println("client's roleId"+client.getRoleId());
                  client.getSession().getBasicRemote().sendText(message);
              }
          }catch (Exception e){
              log.error("给后厨发送消息失败!");
          }
      }
    
      /**
       * 给服务员发送订单消息
       * @return
       */
      public static void sendMessageToWaiter(String message){
          try{
              for (WebSocketClient client: webSocketMap.values()){
                  if (client.getRoleId() != 3) continue;
                  client.getSession().getBasicRemote().sendText(message);
              }
          }catch (Exception e){
              log.error("给服务员发送消息失败!");
          }
      }	
    }
    
  4. 在需要发送实时消息的地方,调用工具类的静态方法
    举例:管理员发布公告后,给除他自己以外的所有在线用户发送一条实时消息

    @RequestMapping("/add")
    @RequiresRoles("ADMIN")
    public boolean addDish(Notice notice){
        notice.setSendTime(new Date());
        WebSocketService.sendAllMessage(notice.getUserId(),"公告");
        return noticeServiceImpl.addNotice(notice);
    }
    
  5. 前端完善相关代码

5. 问题总结

  • Mybatis中实体类属性名和数据库字段名不一致
    eg:数据库 last_name 实体类 lastName
    解决:
    在mapper映射文件中创建resultMap

    <resultMap id="BaseResultMap" type="com.example.demo.entity.Dishes" >
    <!--主键-->
    <id column="id" property="id" jdbcType="INTEGER" />
    <!--其余字段名-->
    <result column="dish_name" property="dishName" jdbcType="VARCHAR" />
    <result column="price" property="price" jdbcType="DOUBLE" />
    </resultMap>
    
    
  • @Autowired自动注入属性出错
    解决:
    先检查是否开启组件扫描
    然后属性类型是否加了组件注解(@Component、@Mapper、@Service)

  • 只传入一个参数进行条件查询时,报错There is no getter for property named ‘id’ in ‘class java.lang.Integer’
    解决:
    xml文件中用_parameter指代这个唯一参数
    在这里插入图片描述

    	<select id="getUser" parameterType="String">
    		select * from user
    		<if test="_parameter != null and _parameter !=''">
    			where name = #{_parameter}
    		</if>
    	</select>
    

    @Param方法解决

  • 在mybatis进行多表查询
    解决:
    参考链接1
    参考链接2
    传入参数和输出参数类型都要变成Map
    传入参数要利用@Param标明参数名

    public List<Map<String,Object>> findSomeDishOrder(@Param("dishName")String dishName,
                                                          @Param("dishState")Integer dishState,
                                                          @Param("tableId")Integer tableId,
                                                          @Param("count")Integer count){
            Map<String,Object> map = new HashMap<>();
            map.put("dishName",dishName);
            map.put("dishState",dishState);
            map.put("tableId",tableId);
            map.put("count",count);
            List<Map<String,Object>> rs = dishOrderService.findSomeDishOrder(map);
            System.out.println(rs.size());
            return dishOrderService.findSomeDishOrder(map);
        }
    

mapper映射文件

 <select id="selectByTest" resultType="java.util.Map" parameterType="Map" >
   SELECT distinct dish_name,table_id,dish_state,count
   FROM dishes
   INNER JOIN dishorder
   ON dishes.dish_id = dishorder.dish_id
   INNER JOIN orderinfo
   ON dishorder.order_id = orderinfo.order_id
   <trim prefix="where" suffixOverrides="and">
     <if test="dishName != null and dishName != ''">
       dish_name = #{dishName,jdbcType=VARCHAR} and
     </if>
     <if test="tableId != null">
       table_id = #{tableId,jdbcType=INTEGER} and
     </if>
     <if test="dishState != null">
       dish_state = #{dishState,jdbcType=INTEGER} and
     </if>
     <if test="count != null">
       count = #{count,jdbcType=INTEGER} and
     </if>
   </trim>
 </select>

6. 其他

  • 结合springboot+mybatis+mysql进行增删查改
    参考链接1
    参考链接2
  • shiro+springboot整合jwt进行身份验证、解决跨域问题
    参考链接
  • springboot配置打印sql语句
    参考链接
    application.yml
      configuration:
    	log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    
  • 将springboot项目部署到服务器
    参考链接1
    参考链接2
  • 规范!规范!规范!
    团队之间涉及合作问题,如果一个人命名或者代码不规范,之后合并起来真的非常痛苦
    务必重视!!!!!!!!!!!!!!
    数据库规范:字段名不同单词之间用下划线分隔
    类规范:成员属性名用小驼峰命名
    springboot目录结构规范:
    controller层
    |
    service层(用来声明方法的service接口类和具体实现方法的serviceImpl类)
    |
    mapper层(声明操作数据库方法名的mapper类和具体写sql语句的mapper映射文件xml)
  • 当不清楚跨越多个类、多个方法的执行顺序时,可以通过断点或者在每个方法内增加所属类所属方法名的控制台输出语句的方式进行分辨
  • lombok使用
    参考链接
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值