舒大少博客

一个95后少年的个人博客

当前时间为:
欢迎大家来到舒大少博客http://admin.evshou.com,广告合作以及淘宝商家推广请微信联系15357240395

2020javaweb教程之高级框架SpringMVC

2021-01-26 08:37:13
swq1822677238

手机扫码查看

2020javaweb教程之高级框架SpringMVC

2020javaweb教程之高级框架SpringMVC

一.开发流程

1.导入依赖:spring-webmvc

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>4.3.6.RELEASE</version>
</dependency>

2.配置核心(前端)控制器

<!--前端控制器-->
<servlet>
  <servlet-name>mvc</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <!--声明配置文件,以支持前端控制器,启动工厂-->
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:mvc.xml</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>mvc</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

3.配置后端控制器

@Controller
@RequestMapping("/hello")
public class HelloController {

    @RequestMapping("/test")
    public String test1(){
        System.out.println("hello world");
        return "";
    }
}

4.配置文件

<!--后端控制器-->
<!--扫描注解的包-->
<context:component-scan base-package="com.evshou.admin"/>
<!--注册注解驱动-->
<mvc:annotation-driven/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/"/>
    <property name="suffix" value=".jsp"/>
</bean>

5.访问

二、接收参数以及解决乱码

1.零散收参

@RequestMapping("/test")
public String test1(Integer id, String username, Date birth){
    System.out.println("id:"+id+",username:"+username);
    System.out.println("birth:"+birth);
    return "index";
}

日期格式转换

@RequestMapping("/test")
public String test1(Integer id, String username,
                    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date birth){
    System.out.println("id:"+id+",username:"+username);
    System.out.println("birth:"+birth);
    return "index";
}

 

2.实体收参

1.导入依赖:lombok

<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.4</version>
  <scope>provided</scope>
</dependency>

2.创建实体类

@Data//get和set方法,toString、hashcode等方法
@AllArgsConstructor//有参构造
@NoArgsConstructor//无参构造
public class Users {
    private Integer id;
    private String username;
    private String password;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;
}

3.控制器

@RequestMapping("/users")
public String testUsers(Users users){
    System.out.println(users);
    return "index";
}

3.数组收参

/*数组收参*/
@RequestMapping("/arrList")
public String testArr(String[] feed){
    for (String str : feed) {
        System.out.println(str);
    }
    return "index";
}
/*表单页面*/
@RequestMapping("/arrListForm")
public String testArrListForm(){
    return "arrList";
}
<form action="${pageContext.request.contextPath}/hello/arrList">
    <input type="checkbox" name="feed" value="apple">苹果 <br>
    <input type="checkbox" name="feed" value="pear">梨子 <br>
    <input type="checkbox" name="feed" value="orange">橘子 <br>
    <input type="submit" value="提交">
    <input type="reset" value="重置">
</form>

 

三、跳转

1.C–>V

@RequestMapping("/test2")
public String test2(){
    System.out.println("test2");
    return "forward:test";
}

2.C–>C

@RequestMapping("/test")
public String test(){
    System.out.println("test");
    return "redirect:/hello/arrListForm";
}

跳转细节

1.在增删改之后,为了防止请求重复提交,重定向跳转

2.在查询之后,可以做转发跳转

jsp细节

1.不应该直接访问jsp,应该先过C,查到数据后,在转发jsp

2.可以将所有jsp都放入 WEB-INF 目录下,即可限制不接受外界直接访问,只能由C转发

传值

C得到数据后,转发V,并向V传递数据。进而V中可以渲染数据,让用户看到含有数据的页面。

转发跳转:request作用域

重定向跳转:session作用域

获得Request和Session

1.导入依赖

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jsp-api</artifactId>
  <version>2.0</version>
  <scope>provided</scope>
</dependency>

2.创建控制层

@RequestMapping("/test1")
public String test1(HttpServletRequest request, HttpSession session){
    request.setAttribute("username","admin");
    session.setAttribute("age",15);
    return "data";
}

3.创建jsp

username:${requestScope.username} <br>
age:${sessionScope.age}

静态资源

在mvc.xml配置文件添加

<mvc:default-servlet-handler/>

四、json处理

SpringMVC默认的json解决方案选择是Jackson,导入Jackson依赖

1.Jackson

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.12.0</version>
</dependency>

@ResponseBody

@Controller
@RequestMapping("/json")
public class JsonController {
    @RequestMapping("/test1")
    @ResponseBody
    public Users test1(){
        return new Users(1,"admin","admin888",new Date());
    }
}

2.FastJson

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.54</version>
</dependency>

配置文件mvc.xml

<!--注册注解驱动-->
<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
            <!--声明转换类型 json-->
            <property name="supportedMediaTypes">
                <list>
                    <value>application/json</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>
@RequestMapping("/test2")
@ResponseBody
public List<Users> test2(){
    return Arrays.asList(
            new Users(1,"admin","admin888",new Date()),
            new Users(2,"admin2","admin888",new Date())
    );
}

@RestController
可以取代 @Controller 和@ResponseBody

五、异常解析器

1.创建exresolver异常解析器包

2.创建异常解析器

public class MyExceptionResolver implements HandlerExceptionResolver {
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
        ModelAndView mv=new ModelAndView();
        ex.printStackTrace();
        /*识别异常*/
        if(ex instanceof NullPointerException){
            mv.setViewName("redirect:xxx");
        }else if(ex instanceof IndexOutOfBoundsException){
            mv.setViewName("redirect:xxx");
        }else mv.setViewName("redirect:xxx");
        return mv;
    }
}

3.创建自定义异常类并继承异常

4.扫描注解

<bean class="com.evshou.admin.exresolver.MyExceptionResolver"/>

5.控制层

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/test1")
    public String test1()  {
        if(1==1) throw new NullPointerException("test1");
        return "index";
    }
}

六、拦截器

1.创建包interceptor

2.创建类并实现HandlerInterceptor

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("登录判断");
        if (httpServletRequest.getSession().getAttribute("users") == null) {
            return true;//放行
        }
        httpServletResponse.sendRedirect("/user/login");//拦截前需要处理响应
        return false;//拦截
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("afterCompletion");
    }
}

3.配置文件

<!--拦截器-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/inter/test1"/><!--拦截单个handler-->
        <mvc:mapping path="/inter/**"/><!--拦截路径下的所有handler-->
        <bean class="com.evshou.admin.interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

4.控制层

@Controller
@RequestMapping("/inter")
public class InterController {
    @RequestMapping("/test1/a/b")
    public String test1(){
        System.out.println("test1");
        return "index";
    }
    @RequestMapping("/test2")
    public String test2(){
        System.out.println("test2");
        return "index";
    }
}

七、文件上传

1.导入依赖

<!--文件上传-->
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.4</version>
</dependency>
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.3</version>
  <exclusions>
    <exclusion>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
    </exclusion>
  </exclusions>
</dependency>

2.创建表单

<form action="" enctype="multipart/form-data" method="post">
    file : <input type="file" name="source"> <br>
    <input type="submit" value="up">
</form>

3.配置文件

<!--上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10485760"/>
</bean>

4.创建控制层

//文件上传
@RequestMapping("/upload")
public String upload(MultipartFile[] filename, HttpServletRequest request) throws IOException {
    if (filename != null) {
        for (MultipartFile multipartFile : filename) {
            String fileName = multipartFile.getOriginalFilename();
            System.out.println("fileName:"+fileName);//fileName:3.png
            //获取文件上传的路径
            String realPath = request.getServletContext().getRealPath("/WEB-INF/uploads");
            String path = uploadDispath(realPath);//返回带有年月日的文件夹
            System.out.println("path:"+path);
            File file=new File(path);
            //获得文件的后缀
            String extension = FilenameUtils.getExtension(fileName);
            //生成唯一的文件名
            String filenames = uploadFilename(fileName);//返回带有年月日时分秒的文件名
            System.out.println("filenames:"+filenames);//filenames:20210123120744_3.png
            //获取文件类型
            String type = multipartFile.getContentType();
            //filename:20210123120744_3.png,type:image/png
            System.out.println("filename:"+filenames+",type:"+type);
            if (!file.exists()) {
                file.mkdirs();
            }else multipartFile.transferTo(new File(file+File.separator+filenames));
            OutputStream os=new FileOutputStream(file+File.separator+filenames);
            os.close();
        }
    }
    return "index";
}
//获取文件列表
public void getFileLists(String path,Map<String,String> filenames){
    //1.路径当成文件对象
    File file=new File(path);
    //2.获取该目录(uploads)下所有内容,包括文件或文件夹
    File[] files = file.listFiles();
    if (files!=null) {
        for (File file1 : files) {
            //如果是文件夹,递归遍历
            if (file1.isDirectory()) {
                getFileLists(file1.getPath(),filenames);
            }else{
                String name = file1.getName();
                //获得原名称和新名称
                String str=name.substring(name.lastIndexOf("_")+1);
                filenames.put(name,str);
            }
        }
    }
}
//文件列表
@RequestMapping("/fileList")
public String fileList(HttpServletRequest request){
    //1.获得下载的目录路径
    String realPath = request.getServletContext().getRealPath("/WEB-INF/uploads");
    //2.创建Map集合 key--图片原名称  value--图片新名称
    Map<String,String> map=new HashMap<>();
    getFileLists(realPath,map);
    request.setAttribute("map",map);
    return "showFileLists";
}
//文件下载
@RequestMapping("/download")
public void download(String filename, HttpServletRequest request,HttpServletResponse response)
        throws IOException {
    System.out.println("filename:"+filename);
    //获取下载的路径
    String realPath = request.getServletContext().getRealPath("/WEB-INF/uploads");
    String newPath = uploadDispath(realPath);
    response.setHeader("content-disposition","attachment;filename="+filename);
    IOUtils.copy(new FileInputStream(newPath+File.separator+filename),response.getOutputStream());
}

文件上传超过大小限制异常

1.创建上传拦截器并实现HandlerInterceptor

2.添加fileSize私有属性并添加getset方法

3.添加内容

@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
    //效验文件大小
    ServletRequestContext ctx=new ServletRequestContext(httpServletRequest);
    long realFileSize=ctx.contentLength();
    if(fileSize>=realFileSize) return true;
    httpServletResponse.sendRedirect(httpServletRequest.getContextPath()+"/error.jsp");
    return false;
}

4.配置mvc文件

<!--文件上传超出大小异常拦截-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/up/**"/>
        <bean class="com.evshou.admin.interceptor.UploadInterceptor">
            <property name="fileSize" value="2097152"/>
        </bean>
    </mvc:interceptor>
</mvc:interceptors>

 

八、验证码

1.导入ValidateCodejar包

2.创建控制层

@Controller
@RequestMapping("/vc")
public class VcodeController {
    @RequestMapping("/")
    public void code(HttpServletResponse response, HttpSession session) throws IOException {
        ValidateCode vc=new ValidateCode(120,50,4,1);
        vc.write(response.getOutputStream());
        session.setAttribute("vc",vc);
    }
}

3.创建页面

<input type="text" id="">
<img src="${pageContext.request.contextPath}/vc/" alt="" id="img">
<a onclick="refreshCode()">看不清,换一张</a>
<script>
    function refreshCode(){
        var img=document.getElementById("img");
        img.src="${pageContext.request.contextPath}/vc/?"+Math.random();
    }
</script>

九、REST

1.标识

GET:查询,POST:增加,PUT:修改,DELETE:删除

示例:
GET:/admin/users 查询所有用户
POST:/admin/users 增加一个用户
PUT:/admin/users/1 修改一个用户
DELETE:/admin/users/1 删除一个用户
GET:/admin/users/1/orders 查询用户1的订单
POST:/admin/users/1/orders 为用户1增加一个订单

@GetMapping("/usersList")//查询所有
public String usersList(){
    System.out.println("query AllUsers");
    return "index";
}
@PostMapping("/user")//添加一个用户
public String addUsers(Users users){
    System.out.println("add Users");
    return "index";
}
@PutMapping("/user")//修改一个用户
public String update(Users users){
    System.out.println("update Users");
    return "index";
}
@DeleteMapping("/user/{id}")//删除一个用户
public String delete(@PathVariable Integer id){
    System.out.println("delete UserById");
    return "index";
}
@GetMapping("/user/{id}")//查询某个用户
public String queryUsersById(@PathVariable Integer id){
    System.out.println("query UsersById");
    return "index";
}
@PostMapping("/user/{id}")//添加指定某个用户id
public String addUsersById(@PathVariable Integer id){
    System.out.println("add UserById");
    return "index";
}

解决

rest过滤器不支持put、delete,浏览器默认会将它们转为get,所以通知过滤器来解决问题,可以定义一个
method=”post”的form,附加一个名为”_method”的请求参数(隐藏域),即可模拟put、delete的请求方式

<!-- 过滤器 -->
<filter>
  <filter-name>HiddenHttpMethodFilter</filter-name>
  <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>HiddenHttpMethodFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

jsp对请求方式的支持

jsp只支持 head、get、post
put、delete、post之后,均应该重定向到get上,再由get转发jsp

ajax请求

场景2:直接发送PUT、DELETE请求

Tomcat不处理put请求,其中参数不接收

<form action="${pageContext.request.contextPath}/rest/user" method="post">
    <input type="hidden" name="_method" value="put">
    <input type="submit" value="提交">
</form>
<script>
    function putX(){
        var xhr=new XMLHttpRequest();
        xhr.open("put","${pageContext.request.contextPath}/rest/users");//ajax正常发送put请求
        xhr.setRequestHeader("content-type","application/x-www-form-urlencoded");
        xhr.send("id=1&username=admin&password=admin888");//携带参数
    }
</script>
<input type="button" onclick="putX()" value="ajax">

解决方案:

<!--put和 delete请求-->
<filter>
  <filter-name>put</filter-name>
  <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>put</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

场景3:直接发送put请求,但携带json格式数据参数

function putXPlus(){
    var xhr=new XMLHttpRequest();
    xhr.open("put","${pageContext.request.contextPath}/rest/users");//ajax正常发送put请求
    xhr.setRequestHeader("content-type","application/json");
    xhr.send('{"id":1,"username":"admin","password":"admin888"}');//携带json数据参数
}

分页

@GetMapping("/user/{pageNum}/{pageSize}")
@ResponseBody
 public List<Users> queryAllUsers(@PathVariable Integer pageNum,@PathVariable Integer pageSize){
    System.out.println("get");
    List<Users> users=new ArrayList<>();
    return users;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注