SpringMVC - 传智燕青 - springmvc_mybatis项目代码

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37546891/article/details/82726782

>> springmvc_mybatis 项目结构

这里写图片描述

>> springmvc_mybatis jar包

这里写图片描述

>> config

~ web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app ......>
    <display-name>springmvc_mybatis</display-name>

    <!-- 加载spring容器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/spring/applicationContext-*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- springmvc前端控制器 -->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>
    </servlet>
    <!-- url-pattern 有3种配置方式:
         1、*.action,访问以.action为结尾的地址,由DispatcherServlet进行解析;
         2、斜杠/,所有访问的地址,都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析;
                                  使用此种方式可以实现RESTful风格的url;
         3、/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面,
                                 仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到Handler,会报错; -->
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>

    <!-- springmvc前端控制器:rest配置 -->
    <servlet>
        <servlet-name>springmvc_rest</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc_rest</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 乱码过滤器:解决post请求乱码问题 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

~ mybatis/SqlMapConfig.xml

<configuration>
    <!-- 全局setting配置,根据需要添加 -->
    <!-- 配置别名 :使用批量扫描别名-->
    <typeAliases><package name="cn.itcast.ssm.po" /></typeAliases>
    <!-- 加载映射文件mapper
         由于使用spring和mybatis的整合包进行mapper扫描,这里就不需要配置了;
         必须遵循:mapper.xml和mapper.java同名且在一个目录; -->
    <!-- <mappers></mappers> -->
</configuration>

~ spring/applicationContext-xxx.xml 文件头

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p" 
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-4.0.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
       http://www.springframework.org/schema/util 
       http://www.springframework.org/schema/util/spring-util-4.0.xsd">
</beans> 

~ spring/applicationContext-dao.xml

<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 加载数据源:使用dbcp;class属性的值在dbcpjar包的org.apache.commons.dbcp2包中 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driver}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <!-- <property name="maxActive" value="10" /> 貌似dbcp2弃用这个属性了 --> 
    <property name="maxIdle" value="5" />
</bean>
<!-- SqlSessionFactory:类在mybatis-spring整合包中 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 加载mybatis的全局配置文件 -->
    <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"></property>
    <!-- 加载数据源:数据库连接池 -->
    <property name="dataSource" ref="dataSource"></property>
</bean>
<!-- mapper扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 指定扫描的包名;如果扫描多个包,不能使用*,每个包中间使用逗号隔开; -->
    <property name="basePackage" value="cn.itcast.ssm.mapper"></property>
    <!-- sqlSessionFactoryBeanName如果使用sqlSessionFactory, 则加载数据库属性的配置文件失效,因为这个先执行 -->
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>

~ spring/applicationContext-service.xml

<!-- 商品管理的service -->
<bean id="itemsService" class="cn.itcast.ssm.service.impl.ItemsServiceImpl"></bean>

~ spring/applicationContext-transaction.xml

<!-- 事务管理器:对mybatis操作数据库事务控制,spring使用jdbc的事务控制类; -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 数据源:dataSource在application-dao.xml文件中配置了 -->
    <property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="save*" propagation="REQUIRED"/>   <!-- 传播行为 -->
        <tx:method name="delete*" propagation="REQUIRED"/>
        <tx:method name="insert*" propagation="REQUIRED"/>
        <tx:method name="update*" propagation="REQUIRED"/>
        <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="select*" propagation="SUPPORTS" read-only="true"/>
    </tx:attributes>
</tx:advice>
<!-- aop -->
<aop:config>
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.itcast.ssm.service.impl.*.*(..))"/>
</aop:config>

~ spring/springmvc.xml

<!-- 批量扫描:可扫描controller、service、...... -->
<context:component-scan base-package="cn.itcast.ssm.controller"></context:component-scan>   

<!-- 静态资源解析:js/css/img... -->
<mvc:resources location="/js/" mapping="/js/**"></mvc:resources>
<mvc:resources location="/img/" mapping="/img/**"></mvc:resources>

<!-- 使用mvc:annotation-driven配置注解映射器和注解适配器配置; -->
<mvc:annotation-driven conversion-service="conversionService" validator="validator"></mvc:annotation-driven>

<!-- 自定义参数绑定:将Converter实现类注入到处理器适配器中 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <!-- 转换器 -->
    <property name="converters">  <!-- 日期转换器 -->
        <list><bean class="cn.itcast.ssm.controller.converter.CustomDateConverter" /></list>
    </property>
</bean>

<!-- 校验器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <!-- hibernate校验器 -->
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
    <!-- 指定校验使用的资源文件,若不能指定,则默认使用classpath下的ValidationMessages.properties -->
    <property name="validationMessageSource" ref="messageSource"></property>
</bean>
<!-- 校验错误信息配置文件 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <!-- 资源文件名 -->
    <property name="basenames">
        <list><value>classpath:CustomValidationMessages</value></list>
    </property>
    <property name="defaultEncoding" value="UTF-8"></property> <!-- 资源文件编码格式 -->
    <property name="cacheSeconds" value="120"></property>      <!-- 对资源文件内容缓存时间,单位秒 -->
</bean> 

<!-- 全局异常处理器:只要实现HandlerExceptionResolver接口就是全局异常处理器 -->
<bean class="cn.itcast.ssm.exception.CustomExceptionResolver"></bean>

<!-- 文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    
    <property name="maxUploadSize"><value>5242880</value></property> <!-- 设置上传文件的最大尺寸为5MB -->
</bean>

<!-- 拦截器:多个拦截器顺序执行 -->
<mvc:interceptors>
    <!-- 登录认证的拦截器 -->
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="cn.itcast.ssm.interceptor.LoginInterceptor"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <!-- /**表示所有url,包括子url路径 -->
        <mvc:mapping path="/**"/>
        <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor2"></bean>
    </mvc:interceptor>
</mvc:interceptors>

<!-- 视图解析器:解析jsp页面,默认使用jstl标签,classpath系需要有jstl的jar包 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/"></property>
    <property name="suffix" value=".jsp"></property>
</bean>

~ CustomValidationMessages.properties

# 添加校验错误提示信息
items.name.length.error=请输入1-30个字符的商品名称
items.creametime.isNull=请输入商品的生产日期

~ db.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8&useSSL=false
jdbc.username=root
jdbc.password=123456

~ log4j.properties

# 日志文件
log4j.rootLogger = debug,stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

>> src

~ ssm.controller/ItemsController.java

 @Controller
// 为了对url进行分类管理,可以在这里定义根路径,最终访问url是根路径+子路径
// 比如:(1)商品列表:/items/queryItems.action
@RequestMapping("/items")
public class ItemsController {
    @Autowired   // 注入ItemsService
    private ItemsService itemsService;

    // 商品分类
    // itemtypes 表示最终将方法返回值放在request中的可以,根据这个值在jsp页面取数据;
    @ModelAttribute("itemtypes")
    public Map<String,String> getItemTypes(){
        Map<String,String> itemTypes = new HashMap<String,String>();
        itemTypes.put("101", "数码");
        itemTypes.put("102", "母婴");
        return itemTypes;
    }

    // (1)商品查询
    @RequestMapping("/queryItems")
    public ModelAndView queryItems(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception {
        // 调用service查找数据库,查询商品列表
        List<ItemsCustom> itemsList = itemsService.findItemsList(itemsQueryVo);
        // 返回ModelAndView
        ModelAndView modelAndView = new ModelAndView();
        // 相当于request的setAttribute,在jsp页面中通过itemsList取数据;
        modelAndView.addObject("itemsList", itemsList);
        // 指定视图:在springmvc.xml文件中的视图解析器中配置了jsp路径的前缀和后缀;
        modelAndView.setViewName("items/queryItems");
        return modelAndView;
    }

    // (2)商品信息修改页面显示
    // method 以数组的方式设置限制http请求方法,可以post+get
    // (7)简单类型参数绑定
    // @RequestParam里面指定request传入参数名称和形参进行绑定;
    // 通过request属性指定参数是否必须传入
    // 通过defaultValue 可以设置默认值,若id参数没有传入,将默认值和形参绑定;
    @RequestMapping(value = "/editItems", method = { RequestMethod.POST, RequestMethod.GET })
    public ModelAndView editItems(@RequestParam(value = "id", required = true) Integer items_id) throws Exception {
        // 调用service根据商品id查询商品信息
        ItemsCustom itemsCustom = itemsService.findItemsById(items_id);
        // 判断商品是否为空,根据id没有查询到商品就抛出异常,提示用户商品信息不存在;
        if(itemsCustom == null){
            throw new CustomException("修改的商品信息不存在!");
        }
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("items", itemsCustom);// 这个items用于editItems.jsp页面获取itemsCustom的数据;
        modelAndView.setViewName("items/editItems");
        return modelAndView;
    }

    // (10)查询商品信息,输出json
    // /itemsView/{id}里面的{id} 表示将这个位置的id参数 传到@PathVariable指定的名称中‘
    @RequestMapping("/itemsView/{id}")
    public @ResponseBody ItemsCustom itemsView(@PathVariable("id") Integer id) throws Exception{
        // 调用service查询商品信息
        ItemsCustom itemsCustom = itemsService.findItemsById(id);
        return itemsCustom;
    }

    // (3)商品信息修改提交
    // (9)在需要校验的pojo前边添加 @Validated,在需要校验的pojo后边添加BindingResult bindingResult 接收出错校验信息;
    // 注意:@Validated 和  BindingResult bindingResult是配对出现的,并且形参顺序是固定的(一前一后)
    // value = { ValidGroup1.class } 指定使用ValidGroup1分组的校验;
    // @ModelAttribute** 可以指定pojo回显到页面在request中的key;
    @RequestMapping("/editItemsSubmit")
    public String editItemsSubmit(Model model, HttpServletRequest request, Integer id, Date creametime,
            @ModelAttribute("items") @Validated(value = { ValidGroup1.class }) ItemsCustom itemsCustom,
            BindingResult bindingResult,
            MultipartFile items_pic      // 从editItems.jsp页面 接收上传的 商品图片
            ) throws Exception {
        // 获取校验错误信息
        if(bindingResult.hasErrors()){
            // 输出错误信息
            List<ObjectError> allErrors = bindingResult.getAllErrors();
            // for (ObjectError objectError : allErrors) {
            //      System.out.println(objectError.getDefaultMessage());
            // }            
            model.addAttribute("allErrors", allErrors); // 将错误信息传到页面            
            model.addAttribute("items", itemsCustom);   // 可以直接使用model将提交的pojo 回显到页面;
            return "items/editItems";                   // 出错重新到商品修改页面
        }
        String originalFilename = items_pic.getOriginalFilename();  // 原始名称
        // 上传图片:原始图片为空说明没有在页面上传图片,则不进行下面上传图片的操作;
        if(items_pic!=null && originalFilename!=null && originalFilename.length()>0){
            String pic_path = "E:\\WorkSpace\\pictureTemp\\"; // 存储图片的物理路径:将图片存储到这里;
            String newFileName = UUID.randomUUID()            // 新图片的名称
                                  + originalFilename.substring(originalFilename.lastIndexOf("."));  
            File newFile = new File(pic_path+newFileName);    // 新图片存储路径+存储名称       
            items_pic.transferTo(newFile);                    // 将内存中的数据写入磁盘
            itemsCustom.setPic(newFileName);                  // 将新图片写到ItemsCustom中
        }   
        itemsService.updateItems(id, itemsCustom); //调用service更新商品信息,页面需要将商品信息传到此方法;
        // ......功能未实现,返回success页面;
        // ModelAndView modelAndView = new ModelAndView();
        // modelAndView.setViewName("success");
        return "success";
    }

    // (4)controller方法返回值返回string:返回逻辑视图名
    @RequestMapping(value = "/editItems1", method = { RequestMethod.POST, RequestMethod.GET })
    public String editItems1(Model model) throws Exception {
        ItemsCustom itemsCustom = itemsService.findItemsById(2);
        // 通过形参中的model将model数据传到页面,相当于ModelAndView的addObject方法;
        model.addAttribute("itemsCustom", itemsCustom);
        return "items/editItems";
    }

    // (5)controller方法返回值返回string:redirect重定向
    // (6)controller方法返回值返回string:forward页面转发
    @RequestMapping("/editItemsSubmit1")
    public String editItemsSubmit1() throws Exception {     
        // return "redirect:queryItems.action";  // (5)重定向到商品查询列表
        return "forward:queryItems.action";      // (6)页面转发到商品查询列表
    }

    // (7)批量删除商品信息
    @RequestMapping("/deleteItems")
    public String deleteItems(Integer[] items_id) throws Exception {
        // 调用service批量删除商品......其他操作...
        return "success";
    }

    // (8)批量修改商品页面,将商品信息查询出来,在页面中可以编辑商品信息
    @RequestMapping("/editItemsQuery")
    public ModelAndView editItemsQuery(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception {
        List<ItemsCustom> itemsList = itemsService.findItemsList(itemsQueryVo);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("itemsList", itemsList);
        modelAndView.setViewName("items/editItemsQuery");
        return modelAndView;
    }
    // (8)批量修改商品提交
    // 通过ItemsQueryVo接收批量提交的商品信息,将商品信息存储到itemsQueryVo中的itemsList属性中;
    @RequestMapping("editItemsAllSubmit")
    public String editItemsAllSubmit(ItemsQueryVo itemsQueryVo) throws Exception {
        return "success";
    }
}

~ ssm.controller/JsonTest.java

@Controller
public class JsonTest {     // json交互测试
    // 请求json串(商品信息),输出json串(商品信息)
    // @RequestBody 将请求的商品信息的json串转成itemsCustom对象;
    // @ResponseBody 将 itemsCustom 转成 json 串输出;
    @RequestMapping("/requestJson")
    public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom){
        // @ResponseBody 将 itemsCustom 转成 json 串输出;
        return itemsCustom;
    }
    // 请求key/value,输出json
    @RequestMapping("/responseJson")
    public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom){
        // @ResponseBody 将 itemsCustom 转成 json 串输出;
        return itemsCustom;
    }   
}

~ ssm.controller/LoginController.java

@Controller
public class LoginController {
    // 登录方法
    @RequestMapping("/login")
    public String login(HttpSession session,String username,String password) throws Exception{
        // 调用service进行用户身份验证
        // ...
        // 在session中保存用户身份信息
        session.setAttribute("username", username);
        // 重定向到商品列表查询页面
        return "redirect:/items/queryItems.action";
    }
    // 退出方法
    @RequestMapping("/logout")
    public String logout(HttpSession session) throws Exception{
        // 清除session,使session状态过期
        session.invalidate();
        // 重定向到商品列表查询页面
        return "redirect:/items/queryItems.action";
    }
}

~ ssm.controller.converter/CustomDateConverter.java

public class CustomDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String source) {
        // 实现将日期串转换成日期类型(格式是:yyyy-MM-dd HH:mm:ss)
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            return simpleDateFormat.parse(source); // 转换之后直接返回
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null; // 若参数绑定失败,则返回null;
    }
}

~ ssm.controller.validation/ValidGroup1/2.java

public interface ValidGroup1 {
    // 接口中不需要定义任何方法,仅是对不同的校验规则进行分组
    // 此分组只校验商品名称的长度
}

~ ssm.exception/CustomException.java

// 系统自定义异常类,针对预期的异常,需要在程序中抛出此类的异常;
public class CustomException extends Exception{ 
    public String message;   // 异常信息
    public CustomException(String message){
        super(message);
        this.message = message;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
}

~ ssm.exception/CustomExceptionResolver.java

// 全局异常处理器
public class CustomExceptionResolver implements HandlerExceptionResolver {
    // ex:系统抛出的异常
    // Handler:处理器适配器要执行的Handler对象(只有method)
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response
                                         , Object handler, Exception ex) {
        // 解析出异常类型
        // 如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示;
        //      String message = null;
        //      if(ex instanceof CustomException){
        //          message = ((CustomException)ex).getMessage();
        //      }else{// 如果该异常类型不是系统自定义的异常,则构造一个自定义的异常类型(信息为“未知错误”)
        //          message = "未知错误";
        //      }
        // 上边代码变为:
        CustomException customException = null;
        if(ex instanceof CustomException){
            customException = (CustomException)ex;
        }else{
            customException = new CustomException("未知错误!");
        }
        String message = customException.getMessage();   // 错误信息
        ModelAndView modelAndView = new ModelAndView();     
        modelAndView.addObject("message", message);  // 将错误信息传到页面
        modelAndView.setViewName("error");           // 指向错误页面
        return modelAndView;
    }
}

~ ssm.interceptor/HandlerInterceptor1/2.java

// 测试拦截器1
public class HandlerInterceptor1 implements HandlerInterceptor {
    // 进入Handler方法之前执行,用于身份认证、身份授权等;
    // 比如:身份认证,若认证不通过,表示当前用户没有登录,需要此方法拦截,不再向下执行;
    @Override
    public boolean preHandle(HttpServletRequest request 
                             , HttpServletResponse response, Object handler)throws Exception {
        System.out.println("HandlerInterceptor1...preHandle");
        // return false表示拦截,不向下执行;
        // return true表示放行;
        return true;
    } 
    // 进入Handler方法之后,返回ModelAndView之前执行;
    // 应用场景从ModelAndView出发:将共用的模型数据(比如菜单导航栏)在这里传到视图,也可以在这里同一指定视图;
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response 
                           , Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
        System.out.println("HandlerInterceptor1...postHandle");
    }
    // 执行Handler完成之后,执行此方法;
    // 应用场景:统一异常处理、统一日志处理;
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response
                                 , Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
        System.out.println("HandlerInterceptor1...afterCompletion");
    }
}

~ ssm.interceptor/LoginInterceptor

// 登录认证的拦截器
public class LoginInterceptor implements HandlerInterceptor {
    // 进入Handler方法之前执行,用于身份认证、身份授权等;
    // 比如:身份认证,若认证不通过,表示当前用户没有登录,需要此方法拦截,不再向下执行;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response
                              , Object handler)throws Exception {
        // 获取请求的url
        String url = request.getRequestURI();
        // 判断url是否是公开地址(实际使用时将公开地址配置在配置文件中)
        // 这里假设公开地址是登录提交的地址
        if(url.indexOf("login.action")>=0){
            return true;    // 如果request域获取到的url是login的url,说明是公开的登录地址,放行;
        }       
        HttpSession session = request.getSession(); // 判断session:先从request域中获取到session
        String username = (String) session.getAttribute("username"); // 从session中取出用户身份信息
        if(username != null){
            return true;    // 如果从session中获取的username不为空,说明身份存在,放行;
        }
        // 执行到这里说明用户身份需要认证,跳转到登录页面;
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        return false;
    } 
    // 进入Handler方法之后,返回ModelAndView之前执行;
    // 应用场景从ModelAndView出发:将共用的模型数据(比如菜单导航栏)在这里传到视图,也可以在这里同一指定视图;
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response
                            , Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    // 执行Handler完成之后,执行此方法;
    // 应用场景:统一异常处理、统一日志处理;
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response
                                 , Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

~ ssm.mapper/ItemsMapperCustom .java

public interface ItemsMapperCustom {
    //查询商品列表
     public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo) throws Exception;
}

~ ssm.mapper/ItemsMapperCustom.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.ssm.mapper.ItemsMapperCustom">
    <!-- 定义商品查询的sql片段,就是商品查询条件 -->
    <sql id="query_items_where">
        <!-- 使用动态sql,通过if判断,满足条件进行拼接; -->
        <!-- 查询条件通过ItemsQueryVo包装对象中的itemsCustom属性进行传递; -->
        <if test="itemsCustom!=null">
            <if test="itemsCustom.name!=null and itemsCustom.name!=''">
                items.name LIKE '%${itemsCustom.name}%'
            </if>
        </if>
    </sql>
    <!-- 商品列表查询 -->
    <!-- parameterType传入包装对象(包装了查询条件)
         resultType建议使用扩展对象 -->
    <select id="findItemsList" parameterType="cn.itcast.ssm.po.ItemsQueryVo" 
            resultType="cn.itcast.ssm.po.ItemsCustom">
            SELECT items.* FROM items
            <where><include refid="query_items_where"></include></where>
    </select>
</mapper>

~ ssm.po/Items.java

public class Items {
    private Integer id;
    // 校验名称在1-30个字符之间;message是提示校验出错显示的信息;
    @Size(min = 1, max = 30, message = "{items.name.length.error}",groups={ValidGroup1.class})
    private String name;
    @NotNull(message = "{items.creametime.isNull}")
    private Date creametime;
    private Float price;
    private String pic;
    private String detail;
    // set/get()......
}

~ ssm.po/ItemsCustom.java

// 商品信息的扩展类
public class ItemsCustom extends Items{
    // 添加商品信息的扩展信息
}

~ ssm.po/ItemsQueryVo.java

public class ItemsQueryVo {  // 商品包装对象类
    private Items items;                 // 商品信息    
    private ItemsCustom itemsCustom;     // 为了系统可扩展性,对原始生成的po进行扩展   
    private List<ItemsCustom> itemsList; // 批量商品信息
    // set/get()......
}

~ ssm.service/ItemsService.java

public interface ItemsService { // 商品管理service
    // (2)根据id查询商品信息
    public ItemsCustom findItemsById(Integer id) throws Exception;
    // (3)修改商品信息
    public void updateItems(Integer id,ItemsCustom itemsCustom) throws Exception;
    // (1)查询商品列表
    public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo) throws Exception;
}

~ ssm.service/ItemsServiceImpl.java

public class ItemsServiceImpl implements ItemsService {  // 商品管理
    @Autowired  // 注入ItemsMapperCustom
    private ItemsMapperCustom itemsMapperCustom;
    @Autowired  // 单表查询商品信息需要注入ItemsMapper
    private ItemsMapper itemsMapper;

    @Override   // (2)根据id查询商品信息
    public ItemsCustom findItemsById(Integer id) throws Exception {
        // 这里使用itemsMapper的方法查询Items单表的信息;
        Items items = itemsMapper.selectByPrimaryKey(id);
        if(items==null){
            throw new CustomException("修改的商品信息不存在!!");
        }
        // 中间对商品信息进行业务处理......实际开发中会有很多操作;
        ItemsCustom itemsCustom = null;
        // 创建ItemsCustom扩展类对象,再将items的属性值拷贝到itemsCustom对象中;
        if(items != null){
            itemsCustom = new ItemsCustom();
            BeanUtils.copyProperties(items, itemsCustom);
        }
        return itemsCustom;
    }

    @Override   // (3)修改商品信息
    public void updateItems(Integer id, ItemsCustom itemsCustom) throws Exception {
        // 添加业务校验,通常在service接口对关键参数进行校验;
        // 校验id是否为空,若为空则抛出异常;
        // 更新商品信息使用下面的方法,根据id更新Items表中的所有字段,包括大文本字段;
        // 下面这个方法updateByPrimaryKeyWithBLOBs,要求必须传入id;
        itemsCustom.setId(id); // 宁可重复set,也要尽可能避免id为空;
        itemsMapper.updateByPrimaryKeyWithBLOBs(itemsCustom);
    }

    @Override    // (1)查询商品列表
    public List<ItemsCustom> findItemsList(ItemsQueryVo itemsQueryVo) throws Exception {
        // 通过ItemsMapperCustom查询数据库
        return itemsMapperCustom.findItemsList(itemsQueryVo);
    }
}

>> jsp

~ jsp/items/editItems.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>修改商品信息</title>
</head>
<body>
    <!-- 显示错误信息 -->
    <c:if test="${allErrors!=null && allErrors.size()>0 }">
        <c:forEach items="${allErrors }" var="error">
            ${error.defaultMessage }<br/>
        </c:forEach>
    </c:if>
    <form id="itemForm" method="post"  enctype="multipart/form-data"
          action="${pageContext.request.contextPath}/items/editItemsSubmit.action">
          <input type="hidden" name="id" value="${items.id}" >
          修改商品信息:
          <table width="100%" border="1">
            <tr><td>商品名称</td>
                <td><input type="text" name="name" value="${items.name}" /></td>
            </tr>
            <tr><td>商品价格</td>
                <td><input type="text" name="price" value="${items.price}" /></td>
            </tr>
            <tr><td>商品生产日期</td>
                <td><input type="text" name="creametime"  
                    value="<fmt:formatDate value="${items.creametime}" 
                    pattern="yyyy-MM-dd HH:mm:ss" />" /></td>
            </tr>
            <tr><td>商品图片</td>
                <td>
                    <c:if test="${items.pic!=null }">
                        <img src="/pic/${items.pic }" width="100" height="100" /><br/>
                    </c:if>
                    <input type="file" name="items_pic" />
                </td>
            </tr>
            <tr><td>商品简介</td>
                <td><textarea rows="3" cols="30" name="detail">${items.detail}</textarea></td>
            </tr>
            <tr><td colspan="2" align="center"><input type="submit" value="提交" /></td></tr>
        </table>
    </form>
</body>
</html>

~ jsp/items/editItemsQuery.jsp

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>查询商品列表</title>
        <script type="text/javascript">
            function editItemsAllSubmit() {  // 提交form
                document.itemsForm.action="${pageContext.request.contextPath}/items/editItemsAllSubmit.action";
                document.itemsForm.submit();
            }
            function queryItems() {          // 提交form
                document.itemsForm.action="${pageContext.request.contextPath}/items/queryItems.action";
                document.itemsForm.submit();
            }
        </script>
    </head>
<body>
    <form name="itemsForm" method="post"
          action="${pageContext.request.contextPath}/items/queryItems.action">
        查询条件:
        <table width="100%" border="1">
            <tr>
                <td>商品名称<input name="itemsCustom.name" /></td>
                <td><input type="button" value="查询" onclick="queryItems()" /></td>
                <td><input type="button" value="批量修改提交" onclick="editItemsAllSubmit()" /></td>
            </tr>
        </table>
        商品列表:
        <table width="100%" border="1">
            <tr>
                <td>商品名称</td>
                <td>商品价格</td>
                <td>生产日期</td>
                <td>商品描述</td>
                <td>操作</td>
            </tr>
            <c:forEach items="${itemsList}" var="item" varStatus="status">
                <tr>
                    <td><input name="itemsList[${status.index }].name" value="${item.name}"></td>
                    <td><input name="itemsList[${status.index }].price" value="${item.price}"></td>
                    <td><input name="itemsList[${status.index }].creametime" 
                               value="<fmt:formatDate value="${item.creametime}" 
                               pattern="yyyy-MM-dd HH:mm:ss" />"></td>
                    <td><input name="itemsList[${status.index }].detail" value="${item.detail}"></td>
                </tr>
            </c:forEach>
        </table>
    </form>
</body>
</html>

~ jsp/items/queryItems.jsp

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>查询商品列表</title>
        <script type="text/javascript">
            function deleteItems() {  // 提交form
                document.itemsForm.action="${pageContext.request.contextPath}/items/deleteItems.action";
                document.itemsForm.submit();
            }
            function queryItems() {  // 提交form
                document.itemsForm.action="${pageContext.request.contextPath}/items/queryItems.action";
                document.itemsForm.submit();
            }
        </script>
    </head>
<body>
    当前用户:${username },
    <c:if test="${username!=null }">
        <a href="${pageContext.request.contextPath}/logout.action">退出</a>
    </c:if>
    <form name="itemsForm" method="post"
          action="${pageContext.request.contextPath}/items/queryItems.action">
        查询条件:
        <table width="100%" border="1">
            <tr><td>
                    商品名称:<input name="itemsCustom.name" />
                    商品类型:
                    <select name="itemtype">
                        <c:forEach items="${itemtypes }" var="itemtype">
                            <option value="${itemtype.key }">${itemtype.value }</option>
                        </c:forEach>
                    </select>
                </td>
                <td><input type="button" value="查询" onclick="queryItems()" /></td>
                <td><input type="button" value="批量删除" onclick="deleteItems()" /></td>
            </tr>
        </table>
        商品列表:
        <table width="100%" border="1">
            <tr>
                <td>选择</td>
                <td>商品名称</td>
                <td>商品价格</td>
                <td>生产日期</td>
                <td>商品描述</td>
                <td>操作</td>
            </tr>
            <c:forEach items="${itemsList}" var="item">
                <tr>
                    <td><input type="checkbox" name="items_id" value="${item.id}" /></td>
                    <td>${item.name}</td>
                    <td>${item.price}</td>
                    <td><fmt:formatDate value="${item.creametime}" pattern="yyyy-MM-dd HH:mm:ss" /></td>
                    <td>${item.detail}</td>
                    <td><a href="${pageContext.request.contextPath}/items/editItems.action?id=${item.id}">修改</a></td>
                </tr>
            </c:forEach>
        </table>
    </form>
</body>
</html>

~ jsp/error.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>错误提示</title>
    </head>
    <body>
        ${message }
    </body>
</html>

~ jsp/login.jsp

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>系统登录</title>
    </head>
    <body>
        <form action="${pageContext.request.contextPath}/login.action" method="post">
            用户账号:<input type="text" name="username"><br/>
            用户密码:<input type="password" name="password"><br/>
            <input type="submit" value="登录" />
        </form>
    </body>
</html>

~ jsp/success.jsp

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>成功</title>
    </head>
    <body>
        操作成功!
    </body>
</html>

~ jsonTest.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>json交互测试</title>
        <script type="text/javascript"    // 引入jQueryjssrc="${pageContext.request.contextPath}/js/jquery-1.11.3.min.js"></script>
        <script type="text/javascript">
            function requestJson(){  // 请求json,输出json
                $.ajax({
                    type:'post',
                    url:'${pageContext.request.contextPath}/requestJson.action',
                    contentType:'application/json;charset=utf-8',
                    data:'{"name":"手机","price":999}',  // 数据格式是json串;
                    success:function(data){  // 返回json结果;
                        alert(data.name);
                    }
                });
            }
            function responseJson(){  // 请求key/value,输出json
                $.ajax({
                    type:'post',
                    url:'${pageContext.request.contextPath}/responseJson.action',
                    // 请求是key/value,这里不需要指定contentType,因为默认就是key/value类型;
                    // contentType:'application/json;charset=utf-8',  // 
                    data:'name=手机&price=998',  // 数据格式是key/value串;
                    success:function(data){
                        alert(data.price);
                    }
                });
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="requestJson()" value="请求json,输出json" />
        <input type="button" onclick="responseJson()" value="请求key/value,输出json" />
    </body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_37546891/article/details/82726782
今日推荐