手机扫码查看
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;
}



发表回复