RainNenya

RainNenya 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

RainNenya 发布了文章 · 2019-03-22

SpringMVC文件上传

SpringMVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。SpringMVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件。

1. 添加pom依赖

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.3</version>
    </dependency>
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.2</version>
    </dependency>

2. 配置文件上传bean

在spring mvc配置文件中增加一个文件上传bean。

    <!-- SpringMVC上传文件时,需要配置MultipartResolver处理器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

3.文件上传

文件上传是项目开发中最常见的功能。为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器。

上传文件界面:upload_form.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>文件上传</title>
</head>
<body>

<!-- 上传单个对象 注意表单的method属性设为post,enctype属性设为multipart/form-data -->
<form method="POST" action="/SpringMVCDemo1/upload" enctype="multipart/form-data">
    <input type="file" name="file" /><br/><br/>
    <input type="submit" value="上传" />
</form>

<!-- 上传多个对象 注意表单的method属性设为post,enctype属性设为multipart/form-data -->
<form method="POST" action="/SpringMVCDemo1/uploadMultiFiles" enctype="multipart/form-data">
    <p>文件1:<input type="file" name="file" /></p>
    <p>文件2:<input type="file" name="file" /></p>
    <p>文件3:<input type="file" name="file" /></p>
    <!-- 同时传递其他业务字段 -->
    <p>用户名:<input type="text" name="userName" /></p>
    <p>密码:<input type="password" name="password" /></p>
    <p><input type="submit" value="上传" /></p>
</form>
</body>
</html>

上传结果返回界面:upload_result.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h2>上传结果为:${message}</h2>
</body>
</html>

注意:要提前创建好存储文件的文件夹,比如我的路径为:"D:staticResourcesTestimgupload"。

FileController.java

@Controller
@RequestMapping("/SpringMVCDemo1")
public class FileController {
    /**
     * 跳转到上传页面
     * @GetMapping 是一个组合注解,是@RequestMapping(method = RequestMethod.GET)的缩写。
     */
    @GetMapping("/gotoUploadForm")
    public String index() {
        return "/upload_form.jsp";
    }

    /**
     * 上传单个文件
     * 通过MultipartFile读取文件信息,如果文件为空跳转到结果页并给出提示;
     * 如果不为空读取文件流并写入到指定目录,最后将结果展示到页面
     * @param multipartFile
     * @PostMapping 是一个组合注解,是@RequestMapping(method = RequestMethod.POST)的缩写。
     */
    @PostMapping("/upload")
    public String uploadSingleFile(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request){
        if (multipartFile.isEmpty()){
            request.setAttribute("message",  "Please select a file to upload '");
            return "/upload_result.jsp";
        }

        try {
            String contentType = multipartFile.getContentType();
            String originalFilename = multipartFile.getOriginalFilename();
            byte[] bytes = multipartFile.getBytes();
            System.out.println("上传文件名为-->" + originalFilename);
            System.out.println("上传文件类型为-->" + contentType);
            System.out.println("上传文件大小为-->"+bytes.length);

            //filePath为存储路径
            String filePath = "d:/staticResourcesTest";
            System.out.println("filePath-->" + filePath);
            //存储在staticResourcesTest下的imgupload文件夹下
            File parentPath = new File(filePath, "imgupload");
            System.out.println("上传目的地为-->"+parentPath.getAbsolutePath());
            try {
                File destFile = new File(parentPath,originalFilename);//上传目的地
                FileUtils.writeByteArrayToFile(destFile,multipartFile.getBytes());
            } catch (Exception e) {
                e.printStackTrace();
            }
            request.setAttribute("message",  "You successfully uploaded '" + multipartFile.getOriginalFilename() + "'");

        } catch (IOException e) {
            e.printStackTrace();
        }
        return "/upload_result.jsp";
    }

    /**
     * 上传多个文件,同时接受业务数据
     * @param origFiles
     * @param request
     * @param user
     * @return
     */
    @PostMapping("/uploadMultiFiles")
    public String uploadMultiFiles(@RequestParam("file") List<MultipartFile> origFiles, HttpServletRequest request, User user) {
        //User为实体类
        System.out.println("User=="+user);
        if (origFiles.isEmpty()) {
            request.setAttribute("message",  "Please select a file to upload '");
            return "/upload_result.jsp";
        }

        try {
            for (MultipartFile origFile : origFiles) {
                String contentType = origFile.getContentType();
                String fileName = origFile.getOriginalFilename();
                byte[] bytes = origFile.getBytes();
                System.out.println("上传文件名为-->" + fileName);
                System.out.println("上传文件类型为-->" + contentType);
                System.out.println("上传文件大小为-->"+bytes.length);

                String filePath = "d:/staticResourcesTest";
                System.out.println("上传目的地为-->"+filePath);
                try {
                    //上传目的地(staticResourcesTest文件夹下)
                    File destFile = new File(filePath,fileName);
                    FileUtils.writeByteArrayToFile(destFile,origFile.getBytes());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            request.setAttribute("message",  "You successfully uploaded '");
        } catch (IOException e) {
            e.printStackTrace();
        }

        return "/upload_result.jsp";
    }
}
查看原文

赞 0 收藏 0 评论 0

RainNenya 发布了文章 · 2019-03-20

ControllerAdvice拦截器

Spring3.2开始提供的新注解,控制器增强(AOP),最主要的应用是做统一的异常处理。@ControllerAdvice(看成spring mvc提供的一个特殊的拦截器)。
@ControllerAdvice是一个@Component,用于定义@ExceptionHandler(最主要用途),@InitBinder@ModelAttribute方法,适用于所有使用@RequestMapping方法(拦截)。

引申:@interface 元注解
@Target(ElementType.TYPE) :该注解应用到什么地方。
@Retention(RetentionPolicy.RUNTIME):什么时候应用。

@ExceptionHandler:为所有controller封装统一异常处理代码。
@ModelAttribute:为所有controller设置全局变量。
@InitBinder:用于为所有controller设置某个类型的数据转换器。

准备:搭建好Spring Boot,页面使用thymeleaf

1.全局异常捕捉处理

ControllerAdviceTest.java

/**
 * 启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,
 * 都会作用在 被 @RequestMapping 注解的方法上
 */
@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 全局异常捕捉处理
     * @ExceptionHandler 用来定义函数针对的异常类型
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map errorHandler(Exception ex){
        Map map = new HashMap();
        map.put("code","0000");
        map.put("msg",ex.getMessage());
        return map;
    }
}

ExceptionController.java

@RestController
public class ExceptionController {
    @RequestMapping("exception1")
    public String exception1() throws IOException {
        return "拦截器测试";
    }
}

浏览器访问:localhost:8080/exception1

浏览器显示:拦截器测试

@RestController
public class ExceptionController {
    @RequestMapping("exception2")
    public String exception2() throws IOException {
        int i = 1/0;
        return "拦截器测试";
    }
}

浏览器访问:localhost:8080/exception2

浏览器显示:{"msg":"/ by zero","code":"0000"}

@RestController
public class ExceptionController {
    @RequestMapping("exception3")
    public String exception3() throws IOException {
        throw new NullPointerException("服务器到非洲去了");
    }
}

浏览器访问:localhost:8080/exception3

浏览器显示:{"msg":"服务器到非洲去了","code":"0000"}

2.拦截捕捉自定义异常

MyException.java

public class MyException extends RuntimeException {
    private String code;
    private String msg;
    //Get、Set方法略……
    public MyException(String code,String msg) {
        this.code = code;
        this.msg = msg;
    }
}

ControllerAdviceTest.java

@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 拦截捕捉自定义异常 MyException.class
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = MyException.class)
    public Map myErrorHandler(MyException ex) {
        Map map = new HashMap();
        map.put("code", ex.getCode());
        map.put("msg", ex.getMsg());
        return map;
    }
}

ExceptionController.java

@RestController
public class ExceptionController {
    @RequestMapping("myException")
    public String myException(){
        throw new MyException("1111","This is my Exception!");
    }
}

浏览器访问:localhost:8080/myException

浏览器显示:{"msg":"This is my Exception!","code":"1111"}


跳转到一个单独的异常显示页面

ControllerAdviceTest.java

@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 跳转视图显示异常
     * @param ex
     * @return
     */
    @ExceptionHandler(value = MyException.class)
    public ModelAndView myErrorHandlerToView(MyException ex) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("myGlobalExceptionPage");
        modelAndView.addObject("code", ex.getCode());
        modelAndView.addObject("msg", ex.getMsg());
        return modelAndView;
    }
}

myGlobalExceptionPage.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>myGlobalExceptionPage</title>
</head>
<body>
    <p th:text="${code}"></p>
    <p th:text="${msg}"></p>
</body>
</html>

浏览器访问:localhost:8080/myException

浏览器显示:1111 This is my Exception!

3.绑定值到Model中

ControllerAdviceTest.java

@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 把值绑定到Model中,使全局@RequestMapping可以获取到该值
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        System.out.println("添加全局变量");
        model.addAttribute("userName", "Jack");
    }
}

ExceptionController.java

@RestController
public class ExceptionController {
    /**
     * 使用注入的ModelMap来取变量
     * @param modelMap
     * @return
     */
    @RequestMapping("modelMapTest1")
    public Object modelMapTest1(ModelMap modelMap){
        Object globalVal = modelMap.get("userName");
        System.out.println("全局变量为:"+globalVal);
        return globalVal;
    }
}

浏览器访问:localhost:8080/modelMapTest1

控制台输出:添加全局变量 全局变量为:Jack

浏览器显示:Jack


ExceptionController.java

@RestController
public class ExceptionController {
    /**
     * 也可以使用@ModelAttribute注解来取变量
     * @param globalVal
     * @return
     */
    @RequestMapping("/modelMapTest2")
    public Object modelMapTest2(@ModelAttribute("userName") String globalVal) {
        System.out.println("全局变量为:"+globalVal);
        return globalVal;
    }
}

浏览器访问:localhost:8080/modelMapTest2

控制台输出:添加全局变量 全局变量为:Jack

浏览器显示:Jack

4.转换日期格式

ControllerAdviceTest.java

@ControllerAdvice
public class ControllerAdviceTest {
    /**
     * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
     * WebDataBinder是用来绑定请求参数到指定的属性编辑器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        System.out.println("initBinder执行");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);  //日期格式是否宽容(只能判断是否需要跳到下个月去)

        /*
         * spring mvc在绑定表单之前,都会先注册这些编辑器,
         * Spring自己提供了大量的实现类,诸如CustomDateEditor,CustomBooleanEditor,CustomNumberEditor等
         * 使用时候调用WebDataBinder的registerCustomEditor方法注册
         */
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat,false));
    }
}

ExceptionController.java

@RestController
public class ExceptionController {
    @RequestMapping("/date")
    public Date index(Date date){
        System.out.println("date="+date);
        return date;
    }
}

浏览器访问:localhost:8080/date?date=2019-3-20

控制台输出:initBinder执行 date=2019-3-20

浏览器显示:"2019-3-20"

查看原文

赞 1 收藏 1 评论 0

RainNenya 发布了文章 · 2019-03-16

Maven多模块之父子关系

Maven多模块项目,适用于一些比较大的项目,通过合理的模块拆分,实现代码的复用,便于维护和管理。尤其是一些开源框架,也是采用多模块的方式,提供插件集成,用户可以根据需要配置指定的模块。

Maven多模块(pom)

1.1 父模块创建

先创建个简单的空的Maven Project作为父项目

父模块步骤1

父模块步骤2

父模块步骤3

1.2 子模块创建

重新创建一个Maven Project作为子项目

子模块步骤1

子模块步骤2

子模块步骤3

1.3 父子模块(继承关系)

注意:此时父子模块为两个独立的项目。

父子项目目录结构

步骤1:子项目中加入<parent>节点,传入父项目完整坐标。

父项目坐标

步骤2:将子项目中的依赖都注释掉。

注释子项目依赖

注意:此时子项目中的没有了Maven Dependencies。

步骤3:将子项目注释的依赖添加到父项目中。

父项目添加依赖

注意:此时子项目中的依赖又添加回来了。

子项目的Maven Dependencies

这种直接在父工程中加入<dependencies>的方式,让子工程可以直接复用依赖,但是缺点是所有的子项目无条件继承父工程所有依赖,所以如果要在父工程中添加依赖只能针对非常通用的依赖。

在父项目中再添加一个依赖。

父模块POM

子项目同时也继承了新添加的依赖。

子项目依赖

那如果不想无条件继承父工程的所有依赖,而想让子项目自行选择需要的依赖又该如何做呢?

1.4 dependencyManagement

在父项目中用<dependencies>节点包裹<dependencies>节点,并且添加的是完整的依赖坐标(gav)

dependencies

此时子项目中的Maven Dependencies又会消失,说明添加<dependencies>节点后,它并不负责相关依赖的下载。

子项目加入相应同样依赖,注意不要加versionversion继承自父项目),需要什么样的依赖就声明什么。

子模块依赖

特别注意,如果父项目提供了groupidversion,则删除子项目坐标中的groupidversion,直接继承父项目相关坐标。

注释子项目节点

dependencyManagement的作用:依赖版本管理器

  1. 本身并不下载任何依赖,只是管理依赖的版本。依赖的下载依然需要单独的<dependencies>(不加dependencyManagement,额外写一个)去做
  2. 如果<dependencies>中的<dependency>没有声明版本号(version),maven会去寻找有无对应的dependencyManagement,当前工程没有就会向上找父工程。如果找到就以dependencyManagement中对应依赖声明的version为准,否则报错version is missing。
查看原文

赞 0 收藏 0 评论 0

RainNenya 评论了文章 · 2019-03-16

SpringMVC接收和响应json数据

前后端的数据交互,除了通过form表单进行提交外,也可以通过ajax向后端传递和接收json格式数据(这种方式可以实现请求数据和页面分离)。本文将总结一下在Spring MVC中接收和响应json数据的几种方式。

准备步骤:
1.导入json相关框架的依赖(比如jackson)。
2.spring mvc的controller方法正常写,如果需要响应json,增加@responsebody注解。
3.在接受json对应的输入参数前,加上@RequestBody注解。
服务端接收json数据还原为java对象,称为反序列化,反之,将java对象作为响应转换为json数据发回给客户端,称为序列化。

注意:因为要使用ajax,所有一定要引入jQuery,切记!

jackson maven依赖:

        <!-- jackson依赖 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.7.0</version>
        </dependency>

一、以实体类接收

背景:当ajax传递的参数较多时,采用参数名匹配的方法不太方便。如果后台有对应的实体类,这时可以选择在客户端将数据封装为json格式传递给后台,后台用对应的实体类进行接收。

客户端:

<button onclick="clickMe()">点我</button>
<script>
    function clickMe() {
        $.ajax({
            type : 'POST',
            url : "acceptJsonByEntity",
            contentType : "application/json;charset=utf-8",
            // 如果想以json格式把数据提交到后台的话,JSON.stringify()必须有,否则只会当做表单提交
            data : JSON.stringify({
                "bookId" : 1,
                "author" : "Jack"
            }),
            // 期待返回的数据类型
            dataType : "json",
            success : function(data) {
                var bookId = data.bookId;
                var author = data.author;
                alert("success:" + bookId+','+author);
            },
            error : function(data) {
                alert("error" + data);
            }
        });
</script>
@responseBody注解是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML。

@RequestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容。一般情况下来说常用其来处理application/json类型。

Controller:

@Controller
public class PassJsonParam {
    @RequestMapping(value="acceptJsonByEntity",method = RequestMethod.POST)
    @ResponseBody
    public Book acceptJsonByEntity(@RequestBody Book book, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println("bookId="+book.getBookId()+", author="+book.getAuthor());
        return book;
    }
}

控制台输出:当前http请求方式为:POST bookId=1, author=Jack

客户端(弹窗):success:1,Jack


如果Controller中的所有方法都需要返回json格式数据,可以使用@RestController注解。

@RestController = @Controller + @ResponseBody

Controller(上面的Controller可以用下面的替换):

@RestController
public class PassJsonParam {
    @RequestMapping(value="acceptJsonByEntity",method = RequestMethod.POST)
    public Book acceptJsonByEntity(@RequestBody Book book, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println("bookId="+book.getBookId()+", author="+book.getAuthor());
        return book;
    }
}

注意:使用了@RestController注解后,Controller的方法无法再返回jsp页面或者html,配置的视图解析器也不会起作用。

二、以map方式接收

背景:前台向后台发送ajax请求并且携带很多参数,而后台并没有对应的实体类进行接收又该如何处理呢?最常见的就是表单,这里可以考虑使用map来解决。因为map的数据结构为key-value形式,所以我们可以遍历搜索框表单,将表单的name作为map的key,表单的value作为map的value。

客户端:

<form id="bookForm">
    <input type="text" name="bookName" id="bookName">
    <input type="text" name="author" id="author" >
    <button onclick="submitForm(event)">提交</button>
</form>

<script>
    function submitForm(event) {
        //阻止form默认事件
        event.preventDefault();
        //得到搜索框数据
        var map = new Map();
        $("#bookForm input").each(function () {
            var value = $(this).val();      //input 值
            var name = $(this).attr('name');
            map.set(name,value);
        })

        //Map转为Json的方法
        var obj= Object.create(null);
        for (var [k,v] of map) {
            obj[k] = v;
        }

        $.ajax({
            type: 'POST',
            contentType:'application/json',
            url: "acceptJsonByMap",
            data: JSON.stringify(obj),
            dataType: 'json',
            success: function (data) {
                var bookName = data.bookName;
                var author = data.author;
                alert("bookName ="+bookName+"; author="+author);
            },
            error: function (data) {
                alert("失败啦");
            }
        });
    }
</script>

Controller:

    @RequestMapping(value="acceptJsonByMap")
    @ResponseBody
    public Map<String,Object> acceptJsonByMap(@RequestBody Map<String,Object> paramsMap, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println(paramsMap);
        return paramsMap;
    }

控制台输出:当前http请求方式为:POST {bookName=Love, author=Frank}

客户端(弹窗):bookName =Love; author=Frank

三、以list方式接收(以json数组形式传递)

客户端:

<button onclick="clickHere()">clickHere</button>
<script>
    function clickHere() {
        var params1 = {
            "bookId":"123",
            "author":"Rose"
        };
        var params2 = {
            "bookId":"321",
            "author":"Jack"
        };
        var list = [];
        list.push(params1);
        list.push(params2);

        $.ajax({
            type: 'POST',
            contentType:'application/json',
            url: "acceptJsonByList",
            data: JSON.stringify(list),
            dataType: 'json',
            success: function (data) {
                for (let i = 0; i < data.length; i++) {
                    var bookId = data[i].bookId;
                    var author = data[i].author;
                    alert("bookId ="+bookId+"; author="+author);
                }
            },
            error: function (data) {
                alert("失败啦");
            }
        });
    }
</script>

注意:传递到后端时,list应为[ { key1 : value1}{ key2 : value2} ]的json格式数据,否则可能会出现Json parse error错误。

Controller:

    @RequestMapping(value="acceptJsonByList")
    @ResponseBody
    public List<Book> acceptJsonByList(@RequestBody List<Book> book, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println(book);
        return book;
    }

注意:这里需要Book实体类进行接收。

控制台输出:当前http请求方式为:POST [entity.Book@1138a75c, entity.Book@22d1cbcf]

客户端(弹窗):bookId =123; author=Rose bookId =321; author=Jack

查看原文

RainNenya 评论了文章 · 2019-03-14

SpringMVC接收和响应json数据

前后端的数据交互,除了通过form表单进行提交外,也可以通过ajax向后端传递和接收json格式数据(这种方式可以实现请求数据和页面分离)。本文将总结一下在Spring MVC中接收和响应json数据的几种方式。

准备步骤:
1.导入json相关框架的依赖(比如jackson)。
2.spring mvc的controller方法正常写,如果需要响应json,增加@responsebody注解。
3.在接受json对应的输入参数前,加上@RequestBody注解。
服务端接收json数据还原为java对象,称为反序列化,反之,将java对象作为响应转换为json数据发回给客户端,称为序列化。

注意:因为要使用ajax,所有一定要引入jQuery,切记!

jackson maven依赖:

        <!-- jackson依赖 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.7.0</version>
        </dependency>

一、以实体类接收

背景:当ajax传递的参数较多时,采用参数名匹配的方法不太方便。如果后台有对应的实体类,这时可以选择在客户端将数据封装为json格式传递给后台,后台用对应的实体类进行接收。

客户端:

<button onclick="clickMe()">点我</button>
<script>
    function clickMe() {
        $.ajax({
            type : 'POST',
            url : "acceptJsonByEntity",
            contentType : "application/json;charset=utf-8",
            // 如果想以json格式把数据提交到后台的话,JSON.stringify()必须有,否则只会当做表单提交
            data : JSON.stringify({
                "bookId" : 1,
                "author" : "Jack"
            }),
            // 期待返回的数据类型
            dataType : "json",
            success : function(data) {
                var bookId = data.bookId;
                var author = data.author;
                alert("success:" + bookId+','+author);
            },
            error : function(data) {
                alert("error" + data);
            }
        });
</script>
@responseBody注解是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML。

@RequestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容。一般情况下来说常用其来处理application/json类型。

Controller:

@Controller
public class PassJsonParam {
    @RequestMapping(value="acceptJsonByEntity",method = RequestMethod.POST)
    @ResponseBody
    public Book acceptJsonByEntity(@RequestBody Book book, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println("bookId="+book.getBookId()+", author="+book.getAuthor());
        return book;
    }
}

控制台输出:当前http请求方式为:POST bookId=1, author=Jack

客户端(弹窗):success:1,Jack


如果Controller中的所有方法都需要返回json格式数据,可以使用@RestController注解。

@RestController = @Controller + @ResponseBody

Controller(上面的Controller可以用下面的替换):

@RestController
public class PassJsonParam {
    @RequestMapping(value="acceptJsonByEntity",method = RequestMethod.POST)
    public Book acceptJsonByEntity(@RequestBody Book book, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println("bookId="+book.getBookId()+", author="+book.getAuthor());
        return book;
    }
}

注意:使用了@RestController注解后,Controller的方法无法再返回jsp页面或者html,配置的视图解析器也不会起作用。

二、以map方式接收

背景:前台向后台发送ajax请求并且携带很多参数,而后台并没有对应的实体类进行接收又该如何处理呢?最常见的就是表单,这里可以考虑使用map来解决。因为map的数据结构为key-value形式,所以我们可以遍历搜索框表单,将表单的name作为map的key,表单的value作为map的value。

客户端:

<form id="bookForm">
    <input type="text" name="bookName" id="bookName">
    <input type="text" name="author" id="author" >
    <button onclick="submitForm(event)">提交</button>
</form>

<script>
    function submitForm(event) {
        //阻止form默认事件
        event.preventDefault();
        //得到搜索框数据
        var map = new Map();
        $("#bookForm input").each(function () {
            var value = $(this).val();      //input 值
            var name = $(this).attr('name');
            map.set(name,value);
        })

        //Map转为Json的方法
        var obj= Object.create(null);
        for (var [k,v] of map) {
            obj[k] = v;
        }

        $.ajax({
            type: 'POST',
            contentType:'application/json',
            url: "acceptJsonByMap",
            data: JSON.stringify(obj),
            dataType: 'json',
            success: function (data) {
                var bookName = data.bookName;
                var author = data.author;
                alert("bookName ="+bookName+"; author="+author);
            },
            error: function (data) {
                alert("失败啦");
            }
        });
    }
</script>

Controller:

    @RequestMapping(value="acceptJsonByMap")
    @ResponseBody
    public Map<String,Object> acceptJsonByMap(@RequestBody Map<String,Object> paramsMap, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println(paramsMap);
        return paramsMap;
    }

控制台输出:当前http请求方式为:POST {bookName=Love, author=Frank}

客户端(弹窗):bookName =Love; author=Frank

三、以list方式接收(以json数组形式传递)

客户端:

<button onclick="clickHere()">clickHere</button>
<script>
    function clickHere() {
        var params1 = {
            "bookId":"123",
            "author":"Rose"
        };
        var params2 = {
            "bookId":"321",
            "author":"Jack"
        };
        var list = [];
        list.push(params1);
        list.push(params2);

        $.ajax({
            type: 'POST',
            contentType:'application/json',
            url: "acceptJsonByList",
            data: JSON.stringify(list),
            dataType: 'json',
            success: function (data) {
                for (let i = 0; i < data.length; i++) {
                    var bookId = data[i].bookId;
                    var author = data[i].author;
                    alert("bookId ="+bookId+"; author="+author);
                }
            },
            error: function (data) {
                alert("失败啦");
            }
        });
    }
</script>

注意:传递到后端时,list应为[ { key1 : value1}{ key2 : value2} ]的json格式数据,否则可能会出现Json parse error错误。

Controller:

    @RequestMapping(value="acceptJsonByList")
    @ResponseBody
    public List<Book> acceptJsonByList(@RequestBody List<Book> book, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println(book);
        return book;
    }

注意:这里需要Book实体类进行接收。

控制台输出:当前http请求方式为:POST [entity.Book@1138a75c, entity.Book@22d1cbcf]

客户端(弹窗):bookId =123; author=Rose bookId =321; author=Jack

查看原文

RainNenya 发布了文章 · 2019-03-11

SpringMVC接收和响应json数据

前后端的数据交互,除了通过form表单进行提交外,也可以通过ajax向后端传递和接收json格式数据(这种方式可以实现请求数据和页面分离)。本文将总结一下在Spring MVC中接收和响应json数据的几种方式。

准备步骤:
1.导入json相关框架的依赖(比如jackson)。
2.spring mvc的controller方法正常写,如果需要响应json,增加@responsebody注解。
3.在接受json对应的输入参数前,加上@RequestBody注解。
服务端接收json数据还原为java对象,称为反序列化,反之,将java对象作为响应转换为json数据发回给客户端,称为序列化。

注意:因为要使用ajax,所有一定要引入jQuery,切记!

jackson maven依赖:

        <!-- jackson依赖 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.7.0</version>
        </dependency>

一、以实体类接收

背景:当ajax传递的参数较多时,采用参数名匹配的方法不太方便。如果后台有对应的实体类,这时可以选择在客户端将数据封装为json格式传递给后台,后台用对应的实体类进行接收。

客户端:

<button onclick="clickMe()">点我</button>
<script>
    function clickMe() {
        $.ajax({
            type : 'POST',
            url : "acceptJsonByEntity",
            contentType : "application/json;charset=utf-8",
            // 如果想以json格式把数据提交到后台的话,JSON.stringify()必须有,否则只会当做表单提交
            data : JSON.stringify({
                "bookId" : 1,
                "author" : "Jack"
            }),
            // 期待返回的数据类型
            dataType : "json",
            success : function(data) {
                var bookId = data.bookId;
                var author = data.author;
                alert("success:" + bookId+','+author);
            },
            error : function(data) {
                alert("error" + data);
            }
        });
</script>
@responseBody注解是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML。

@RequestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容。一般情况下来说常用其来处理application/json类型。

Controller:

@Controller
public class PassJsonParam {
    @RequestMapping(value="acceptJsonByEntity",method = RequestMethod.POST)
    @ResponseBody
    public Book acceptJsonByEntity(@RequestBody Book book, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println("bookId="+book.getBookId()+", author="+book.getAuthor());
        return book;
    }
}

控制台输出:当前http请求方式为:POST bookId=1, author=Jack

客户端(弹窗):success:1,Jack


如果Controller中的所有方法都需要返回json格式数据,可以使用@RestController注解。

@RestController = @Controller + @ResponseBody

Controller(上面的Controller可以用下面的替换):

@RestController
public class PassJsonParam {
    @RequestMapping(value="acceptJsonByEntity",method = RequestMethod.POST)
    public Book acceptJsonByEntity(@RequestBody Book book, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println("bookId="+book.getBookId()+", author="+book.getAuthor());
        return book;
    }
}

注意:使用了@RestController注解后,Controller的方法无法再返回jsp页面或者html,配置的视图解析器也不会起作用。

二、以map方式接收

背景:前台向后台发送ajax请求并且携带很多参数,而后台并没有对应的实体类进行接收又该如何处理呢?最常见的就是表单,这里可以考虑使用map来解决。因为map的数据结构为key-value形式,所以我们可以遍历搜索框表单,将表单的name作为map的key,表单的value作为map的value。

客户端:

<form id="bookForm">
    <input type="text" name="bookName" id="bookName">
    <input type="text" name="author" id="author" >
    <button onclick="submitForm(event)">提交</button>
</form>

<script>
    function submitForm(event) {
        //阻止form默认事件
        event.preventDefault();
        //得到搜索框数据
        var map = new Map();
        $("#bookForm input").each(function () {
            var value = $(this).val();      //input 值
            var name = $(this).attr('name');
            map.set(name,value);
        })

        //Map转为Json的方法
        var obj= Object.create(null);
        for (var [k,v] of map) {
            obj[k] = v;
        }

        $.ajax({
            type: 'POST',
            contentType:'application/json',
            url: "acceptJsonByMap",
            data: JSON.stringify(obj),
            dataType: 'json',
            success: function (data) {
                var bookName = data.bookName;
                var author = data.author;
                alert("bookName ="+bookName+"; author="+author);
            },
            error: function (data) {
                alert("失败啦");
            }
        });
    }
</script>

Controller:

    @RequestMapping(value="acceptJsonByMap")
    @ResponseBody
    public Map<String,Object> acceptJsonByMap(@RequestBody Map<String,Object> paramsMap, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println(paramsMap);
        return paramsMap;
    }

控制台输出:当前http请求方式为:POST {bookName=Love, author=Frank}

客户端(弹窗):bookName =Love; author=Frank

三、以list方式接收(以json数组形式传递)

客户端:

<button onclick="clickHere()">clickHere</button>
<script>
    function clickHere() {
        var params1 = {
            "bookId":"123",
            "author":"Rose"
        };
        var params2 = {
            "bookId":"321",
            "author":"Jack"
        };
        var list = [];
        list.push(params1);
        list.push(params2);

        $.ajax({
            type: 'POST',
            contentType:'application/json',
            url: "acceptJsonByList",
            data: JSON.stringify(list),
            dataType: 'json',
            success: function (data) {
                for (let i = 0; i < data.length; i++) {
                    var bookId = data[i].bookId;
                    var author = data[i].author;
                    alert("bookId ="+bookId+"; author="+author);
                }
            },
            error: function (data) {
                alert("失败啦");
            }
        });
    }
</script>

注意:传递到后端时,list应为[ { key1 : value1}{ key2 : value2} ]的json格式数据,否则可能会出现Json parse error错误。

Controller:

    @RequestMapping(value="acceptJsonByList")
    @ResponseBody
    public List<Book> acceptJsonByList(@RequestBody List<Book> book, HttpServletRequest request){
        System.out.println("当前http请求方式为:"+request.getMethod());
        System.out.println(book);
        return book;
    }

注意:这里需要Book实体类进行接收。

控制台输出:当前http请求方式为:POST [entity.Book@1138a75c, entity.Book@22d1cbcf]

客户端(弹窗):bookId =123; author=Rose bookId =321; author=Jack

查看原文

赞 2 收藏 0 评论 4

RainNenya 发布了文章 · 2019-03-01

Hibernate之CRUD与实例状态

在上一篇《初识Hibernate》中简单介绍了在Hibernate如何加载对象和持久化对象,以及Hibernate中对象实例状态。本文将继续介绍Hibernate简单的增删改查方法和对对象实例状态的理解(查询方法暂不提及)。

一、HibernateのCRUD操作

1.1 HibernateのCreate

    @Test
    public void testCreate() {
        Session session = HibernateUtils.getSession();
        User user = new User();
        user.setId(3);
        user.setUserName("Sandy");
        user.setPassWord("aaa");
        session.save(user);
    }

注意:Hibernate事务默认是关闭的,执行后不会报错,但是数据并没有成功插入数据库。

控制台输出:Schema update complete

解决办法:手动设置事务提交

    @Test
    public void testCreate() {
        Session session = HibernateUtils.getSession();
        Transaction tx = session.beginTransaction();
        User user = new User();
        user.setId(3);
        user.setUserName("Sandy");
        user.setPassWord("aaa");
        session.save(user);
        tx.commit();
    }

控制台输出:Hibernate: insert into tbl_user (username, password, id) values (?, ?, ?)

save()方法把一个临时对象加入到Session缓存中,并持久化该临时对象,计划执行一个insert语句。

1.2 HibernateのRead

这里的查询准确来说应该称为对象加载

Hibernate中session.get()方式获取被称为对象加载,只能从数据库中加载出唯一一条记录。查询多条数据Hibernate另提供了API。
    @Test
    public void testRead() {
        Session session = HibernateUtils.getSession();
        Transaction tx = session.beginTransaction();
        User user = (User)session.get(User.class, 3);
        System.out.println(user);
        tx.commit();
    }

控制台输出:Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
User{id=3, userName='Sandy', passWord='aaa'}

get()load() 试图从数据库加载一个实体对象时,Session先判断对象是否存在,如果存在就不到数据库中检索。返回的对象都位于Session缓存中,接下来修改了持久化对象的属性后,当Session清理缓存时,会根据持久化对象的属性变化来同步更新数据库。

区别:

​ (1)当数据库中不存在与OID对应的记录时,load()方法抛出ObjectNotFoundException异常,而get()方法返回null.

​ (2)两者采用不同的检索策略。

​ 默认情况下,load()方法采用延迟检索策略(Hibernate不会执行select语句,仅返回实体类的代理类实例,占用内存很少);而get()采用立即检索策略(Hibernate会立即执行select语句)。

使用场合:

​ (1)如果加载一个对象的目的是为了访问它的各个属性,可以用get();

​ (2)如果加载一个对象的目的是为了删除它,或者建立与别的对象的关联关系,可以用load() ;

1.3 HibernateのUpdate

更新操作并没有使用session.update()方法,直接tx.commit()便能够成功更新数据。session.upate()方法另有作用。
    @Test
    public void testUpdate() {
        Session session = HibernateUtils.getSession();
        Transaction tx = session.beginTransaction();
        User user = (User)session.get(User.class, 3);
        user.setUserName("Bob");
        user.setPassWord("123");
        // 脏数据(Dirty Data)
        // 过时数据检测(前提是该对象是持久态)
        tx.commit();
    }

控制台输出:Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
Hibernate: update tbl_user set username=?, password=? where id=?

Session在清理缓存的时候会自动进行脏检查(dirty-check),如果发现Session缓存中的对象与数据库中相应的记录不一致,就会同步数据库。

1.4 HibernateのDelete

    @Test
    public void testDelete() {
        Session session = HibernateUtils.getSession();
        Transaction tx = session.beginTransaction();
        User user = (User)session.get(User.class, 3);
        user.setUserName("Bob");
        user.setPassWord("123");
        session.delete(user);
        tx.commit();
    }

控制台输出:Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
Hibernate: delete from tbl_user where id=?

计划执行一个delete语句,把对象从Session缓存中删除。

1.5 saveOrUpdate

同时包含了save()和update()方法的功能。如果传入的是临时对象,就调用save()方法;如果传入的是游离对象,就调用update()方法如果传入的是持久化对象,就直接返回。
    @Test
    public void testSaveOrUpdate() {
        Session session = HibernateUtils.getSession();
        Transaction tx = session.beginTransaction();
        User user = new User();
        user.setId(5);
        user.setUserName("Sandy");
        user.setPassWord("123");
        session.saveOrUpdate(user);

        User user2 = (User)session.get(User.class, 1);
        user2.setUserName("Andy");
        user2.setPassWord("apple");
        session.saveOrUpdate(user2);
        tx.commit();
        session.close();
    }

控制台输出:Hibernate: select user_.id, user_.username as username2_8_, user_.password as password3_8_ from tbl_user user_ where user_.id=?
Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
Hibernate: insert into tbl_user (username, password, id) values (?, ?, ?)
Hibernate: update tbl_user set username=?, password=? where id=?

update()方法把游离对象加入当前Session缓存中,计划执行update语句。当update()方法关联一个游离对象时,如果session缓存中已经有一个同类型且ID相同的持久化对象,那么update()方法会抛出NonUniqueException异常。当update()方法关联一个持久化对象时,该方法不起作用。

close():清空session缓存。

二、Hibernateの实例状态

Hibernate中的对象有3中状态,瞬时对象(TransientObjects)、持久化对象(PersistentObjects)和离线对象(DetachedObjects也叫做脱管对象)。

Hibernate对象状态转换图

Java对象在Hibernate持久化层的状态:

  1. 瞬时(transient)状态:刚用new语句创建,还没有被持久化,并且不处于session缓存中(处于临时状态的对象成为临时对象)。
  2. 持久化(Persistent)状态:已经被持久化,并且加入到session缓存中。处于持久化状态的对象称为持久化对象。
  3. 游离(Detached)状态:已经被持久化,但不再处于session缓存中。处于游离状态的对象称为游离对象。
  4. 删除状态:不再处于session缓存中,并且session已经计划将其从数据库中删除。
    @Test
    public void testState() {
        Session session = HibernateUtils.getSession();
        Transaction tx = session.beginTransaction();
        // 持久态对象
        // 1.在数据库中有唯一一条记录关联 2.必须跟一个session关联(必须纳入Hibernate容器)
        User user = (User)session.get(User.class, 1);

        // 临时态
        // User user = new User();

        user.setUserName("Fancy");
        user.setPassWord("abc");

        // 脏数据(Dirty Data)过时数据检测(前提是该对象是持久态)
        tx.commit();
        // 关闭session
        session.close();

        // 游离态(Detached)
        // 1.在数据库中有唯一一条记录对应 2.当前user没有跟Hibernate的session关联(曾经跟Hibernate关联,现在没有)
        // 无法进行脏数据检测
        System.out.println(user);

        //把游离态对象变为持久态(再次纳入Hibernate容器管理,再跟一个session关联起来)
        Session session2 =HibernateUtils.getSession();
        Transaction tx2 = session2.beginTransaction();
        user.setUserName("Kathy");
        user.setPassWord("good");

        //把游离态对象同一个session关联,将对象状态变为持久态
        session2.update(user);
        tx2.commit();
    }
}

控制台输出:Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
User{id=1, userName='Fancy', passWord='abc'}
Hibernate: update tbl_user set username=?, password=? where id=?

查看原文

赞 1 收藏 1 评论 0

RainNenya 发布了文章 · 2019-02-27

初识Hibernate

hibernate_logo

一、什么是Hibernate?

Hibernate (开放源代码的对象关系映射框架): Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的ORM框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

<!-- more -->

二、为什么使用Hibernate?

2.1 Hibernate相对于传统JDBC的优点

  1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
  2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作。
  3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
  4. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。

2.2 Hibernate相对于MyBatis的区别与联系

两者区别:

Hibernate与MyBatis

两者联系:

缓存方面

相同点:

Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓 存方案,创建适配器来完全覆盖缓存行为。

不同点:

Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。

MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。

三、Hibernate的使用

准备好User实体类和数据库记录

User.java

public class User {
    private Integer id;
    private String userName;
    private String passWord;
    //Get、Set方法,此处省略。
}

mysql数据库:

mysql数据库

3.1 添加pom依赖

Hibernate基础Maven依赖:

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <!-- 添加hibernate的依赖 开始-->
    <dependency>
      <groupId>dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>1.6.1</version>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1.1</version>
    </dependency>
    <!-- http://mvnrepository.com/artifact/org.hibernate/hibernate -->
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>4.3.2.Final</version>
    </dependency>

    <dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
      <version>3.2.1</version>
    </dependency>
   <!-- <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib-nodep</artifactId>
      <version>3.1</version>
    </dependency>
    &lt;!&ndash; Hibernate library dependecy end &ndash;&gt;
    <dependency>
      <groupId>javax.transaction</groupId>
      <artifactId>jta</artifactId>
      <version>1.1</version>
    </dependency>-->
    <!-- 添加hibernate的依赖 结束-->
    <!-- mysql数据库的驱动包 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.6</version>
    </dependency>
  </dependencies>

3.2 hibernate.cfg.xml配置文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!--<property name="hibernate.bytecode.use_reflection_optimizer">false</property>-->
        <!--指定数据库的驱动程序-->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <!--指定连接数据库的口令-->
        <property name="hibernate.connection.password">admin</property>
        <!--指定连接数据库的URL-->
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/Hibernatetraning</property>
        <!--指定连接数据库的用户名-->
        <property name="hibernate.connection.username">root</property>
        <!--数据库方言,用于指定使用的sql从属于哪个数据库-->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <!--如果为true,表示在程序运行时会在控制台输出SQL语句,有利于跟踪Hibernate的运行状态,默认为false。应用开发阶段设置为true,发布阶段应设置为false提高运行性能-->
        <property name="show_sql">true</property>
       <!-- <property name="hibernate.hbm2ddl.auto">update</property>-->
        <mapping resource="mapper/User.hbm.xml"></mapping>
    </session-factory>
</hibernate-configuration>

3.2 User.hbm.xml映射文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 4.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.entity.User" table="tbl_user">
        <!--  在User里面 id 的set 和 get 方法里 也要设置为Integer类型的,不然会报错 -->
        <id name="id" column="id" type="java.lang.Integer">
            <generator class="assigned"/>
        </id>
        <property name="userName" column="username"  type="java.lang.String" length="20" />
        <property name="passWord" column="password"  type="java.lang.String" length="20"/>

    </class>
</hibernate-mapping>

测试

        Configuration config = new Configuration().configure();
        SessionFactory sessionFactory = config.buildSessionFactory();

        //测试session是否创建,以及是否可以从user映射的表里获取记录
        Session session = sessionFactory.openSession();
        //System.out.println("session=="+session);
        User user = (User)session.get(User.class,1);
        System.out.println(user);
        //关闭会话工厂,项目自动停止。生产环境中千万不要写这句。
        //sessionFactory.close();

控制台输出:User{id=1, userName='Jack', passWord='123'}

四、Hibernate基本概念

Hibernate是自动化程度更高ORM(Object-Relational Mapping)框架,不是面向SQL的持久层框架,以更加OO方式来编写数据读写代码。

Hibernate

4.1 对象与关系型数据库

对象与关系型数据库

注意:一定要清楚当前操作的东西,是属于对象层面的还是关系型数据库层面的,解决异常也是如此。

Hibernate核心架构

Hibernate中的对象有3中状态,瞬时对象(Transient Objects)、持久化对象(Persistent Objects)和离线对象(Detached Objects也叫做脱管对象)。

4.2 HibernateUtils.java工具类

public class HibernateUtils {

    private static SessionFactory sessionFactory = null;

    static {
        try {
            Configuration configuration = new Configuration().configure();
            ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
                    .applySettings(configuration.getProperties())
                    .build();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        }catch (HibernateException e){
            System.out.println("SessionFactory初始化失败");
            e.printStackTrace();
        }
    }

    public static SessionFactory getSessionFactory() throws Exception{
        if (sessionFactory != null){
            return sessionFactory;
        }else {
            throw new Exception("sessionFactory为空,请检查配置文件");
        }
    }

    public static Session getSession(){
        Session session = null;
        try {
            if (sessionFactory != null){
                session = sessionFactory.openSession();
            }
        }catch (HibernateException e){
            e.printStackTrace();
        }
        return session;
    }

    public static void closeSession(Session session){
        try {
            if (session != null && session.isOpen()){
                session.close();
            }
        }catch (HibernateException e){
            e.printStackTrace();
        }
    }
}

4.3 瞬时对象与持久化对象

测试代码:

        Session session = HibernateUtils.getSession();
        Transaction tx = session.beginTransaction();

        User user1 = new User();
        user1.setId(2);
        user1.setUserName("Frank");
        user1.setPassWord("111");
        // 当前user1在数据库中没有记录进行关联,所以此时user1是瞬时对象。

        // 将user1持久化
        session.save(user1);
        tx.commit();

        User user2 = (User)session.get(User.class, 2);
        System.out.println(user2);
        // 当前user2在数据库有唯一一条记录对应,所以此时user2是持久化对象。

4.4 hibernate.hbm2ddl.auto

hibernate.cfg.xml配置文件中hibernate.hbm2ddl.auto属性值(从类自动生成数据库DDL操作)

<property name="hibernate.hbm2ddl.auto">update</property>设置为update可以不用手动建表了。

  1. create:如果设置为该值,则每次加载hibernate时(准确说应是创建SessionFactory时)都会删除以前创建的表而根据model重新生成表,即使前后的表没有任何变化,通常会造成数据库数据丢失,需谨慎使用这个取值。
  2. create-drop:与create差不多,所不同的是每次sessionFactory关闭时,就会删除所有表。
  3. update(最常用):这个取值比较常用,需要先建立数据库,在第一次加载hibernate时会自动创建表,以后创建hibernate会自动根据model更新表结构,即使表结构改变了,以前的行不会被删除。
  4. validate:每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
查看原文

赞 0 收藏 0 评论 0

RainNenya 发布了文章 · 2019-02-25

Spring MVC常用客户端参数接收方式

Spring MVC常用客户端参数接收方式

在MVC结构中,控制器组件主要的功能就是接收请求、处理请求、生成响应,接收客户端传来的请求参数的往往是控制器要做的第一件事。

Book实体类Book.java

public class Book {
    private Integer bookId;
    private String author;
    //生成Get、Set方法,此处省略
}

一、直接用参数名匹配请求参数

客户端界面(表单):

<form action="/queryString" method="post">
    <input type="text" name="bookId">
    <input type="text" name="author">
    <input type="submit" value="提交">
</form>

controller层:

@Controller
public class ParamPassDemo {
    @RequestMapping(value="/queryString")
    public String test1(Integer bookId, String author) {
        System.out.println("bookId="+bookId+", author="+author);
        //此处返回的地址为(/WEB-INF/jsp/index.jsp)
        return "index";
    }
}

注意:这里@RequestMapping中只有value属性,value可以省略不写。

客户端输入:123,Rose

控制台输出:bookId=123, author=Rose

二、通过@RequestParam注解来指定请求参数的name

客户端界面(表单):

<form action="/queryStringWithSpecName" method="post">
    <input type="text" name="bookId" value="321">
    <input type="text" name="author" value="Jack">
    <input type="submit" value="提交">
</form>
如果表单中的字段与方法中的参数名一致,可以不需要@RequestParam,Spring会自动处理。

controller层:

@Controller
public class ParamPassDemo {
    @RequestMapping("/queryStringWithSpecName")
    public String test2(@RequestParam(value="bookId",required=false) Integer id, @RequestParam("author") String name) {
        System.out.println("bookId="+id+", author="+name);
        return "index";
    }
}

注意:这里@RequestParam中有两个属性,value不能省略。

@RequestParam将请求地址中的参数传递给目标方法,在处理方法入参处使用可以把请求参数传递给请求方法。

当使用@RequestParam注解时,设置客户端传递的请求参数name="bookId"和@RequestParam的value值value="bookId"相匹配后,参数名int id可以和请求参数不匹配。

客户端输入:321, Jack

控制台输出:bookId=321, author=Jack


客户端界面(ajax):

<button onclick="clickMe()">点我</button>
<script>
    function clickMe() {
            $.ajax({
            type : 'POST',
            url : "/queryStringWithSpecName",
            data : {
                "bookId" : 1,
                "author" : "Jack"
            },
        });
    }
</script>

controller层:(不变)

客户端: data:{"author" : "Jack"}

控制台输出: bookId=null, author=Jack(如果bookId为int类型,控制台会抛出异常)

客户端: data:{"bookId" : 1}

控制台输出: org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'author' is not present

通过required设置可选参数,requiredfalse时表示可以不带参数,为true时表示必须带参数(默认值为true)。

当可选参数不存在时,Spring默认将其赋值为空(null),但由于bookId已定义为基本类型int,所以赋值会失败。解决方法:采用int包装类Integer。

三、使用领域对象来接收参数

客户端界面(表单):

<form action="/queryStringWithDomainObj" method="post">
    <input type="text" name="bookId">
    <input type="text" name="author">
    <input type="submit" value="提交">
</form>

controller层:

@Controller
public class ParamPassDemo {
    @RequestMapping("/queryStringWithDomainObj")
    public String test3(Book book) {
        System.out.println("bookId="+book.getBookId()+", author="+book.getAuthor());
        return "index";
    }
 }

客户端输入:111, Bob

控制台输出:bookId=111, author=Bob

四、URL动态参数传递(路径参数)

客户端界面(超链接):

<a href="/book/1">testPathVariable</a>

controller层:

@Controller
public class ParamPassDemo {
    //@PathVariable可以用来映射URL中的占位符到目标方法的参数中
    @RequestMapping("/book/{bookId}")
    public String test4(@PathVariable("bookId") Integer bookId) {
        System.out.println("bookId:" + bookId);
        return "index";
    }
 }

控制台输出:bookId:1

@PathVariable 映射 URL 绑定的占位符

通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中。

五、使用HttpServletRequest获取请求参数

客户端界面(表单):

<form action="/queryBook" method="post">
    <input type="text" name="bookId">
    <input type="text" name="author">
    <input type="submit" value="提交">
</form>

controller层:

@Controller
public class ParamPassDemo {
    @RequestMapping("/queryBook")
    public String test5(HttpServletRequest request) {
        System.out.println("bookId:" + request.getParameter("bookId"));
        //此处index.jsp界面在WEB-INF下
        return "redirect:/index.jsp";
    }
 }

客户端输入:123

控制台输出:用户id:123

六、跳转到另一个controller方法

客户端界面(url地址栏):

http://localhost:8080/test6?bookId=321

controller层:

@Controller
public class ParamPassDemo {
    @RequestMapping("/test6")
    public String test6(String bookId){
        System.out.println("bookId="+bookId);
        //使用服务端跳转的方式转向到另一个controller
        //return "forward:queryBook?bookId="+bookId;
        return "redirect:queryUser?bookId="+bookId;
    }
 }

控制台输出:bookId=321 bookId:321

查看原文

赞 3 收藏 3 评论 0

RainNenya 发布了文章 · 2019-02-19

MyBatis分页插件PageHelper

MyBatis分页插件PageHelper

如果你也在用 MyBatis,建议尝试该分页插件,这一定是最方便使用的分页插件。分页插件支持任何复杂的单表、多表分页。

PageHelper

PageHelper是一个Mybatis的分页插件, 负责将已经写好的sql语句, 进行分页加工.

PageHelper的使用

优点无需你自己去封装以及关心sql分页等问题,使用很方便,前端取数据也很方便。

1.引入pagehelper依赖

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.2<ersion>
</dependency>

2.配置applicationContext.xml文件

在spring的sqlsessionfactorybean中增加一个分页拦截器属性
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="plugins">
                <array>
                    <bean class="com.github.pagehelper.PageInterceptor">
                        <property name="properties">
                            <value>
                                <!-- 这里设定你的数据库类型 -->
                               helperDialect=mysql
                            </value>
                        </property>
                    </bean>
                </array>
    </property>
</bean>

3.调用PageHelper的方法

在service方法中调用PageHelper的静态方法startPage(注意一定要在实际查询数据库之前调用该方法),传入需要查询的页号和每页大小,返回PageHelper插件提供的PageInfo对象。即可自动完成数据库物理分页,无须在你的sql语句中手工加limit子句

startPage方法

4. PageInfo的结构

关于PageInfo的结构请参看源码,这里通过返回的json来展示。根据需要取PageInfo对象的相应属性即可。

PageInfo的结构

查看原文

赞 13 收藏 10 评论 3

认证与成就

  • 获得 20 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2019-01-22
个人主页被 304 人浏览